跟我一起学docker
一、认识
1.什么是docker
Docker 是一个开源项目,诞生于 2013 年初,最初是 dotCloud 公司内部的一个业余项目。它基于 Google 公司推出的 Go 语言实现。 项目后来加入了 Linux 基金会,遵从了 Apache 2.0 协议,项目代码在 GitHub 上进行维护。
Docker 自开源后受到广泛的关注和讨论,以至于dotCloud 公司后来都改名为 Docker Inc。Redhat已经在其 RHEL6.5 中集中支持 Docker;Google 也在其 PaaS 产品中广泛应用。
Docker的主要目标:
通过对应用组件的封装、分发、部署、运行等生命周期的管理,达到应用级别的一次封装,到处运行。
小贴士:这里的应用组件,可以是WEB应用,也可以是一套数据库服务,甚至可以是一个操作系统编译器
2.为什么使用docker
Docker容器虚拟化的优点:
- 环境隔离;
通过cgroups和namesapce进行实现资源隔离,实现一台机器运行多个容器互不影响。
- 更快速的交付部署;
使用docker,开发人员可以利用镜像快速构建一套标准的研发环境;开发完成后,测试和运维人员可以直接通过使用相同的环境来部署代码。Docker可以快速创建和删除容器,实现快速迭代,大量节约开发、测试、部署的时间。并且,各个步骤都有明确的配置和操作,整个过程全程课件,使团队里更容易理解应用创建和工作的过程。
- 更高效的资源利用;
docker容器的运行不需要额外的虚拟化管理程序的支持,它是内核级的虚拟化,可以实现更高的性能,同时对资源的额外需求很低。
- 更易迁移扩展;
docker容器几乎可以在任意的平台上运行,包括乌力吉、虚拟机、公有云、私有云、个人电脑、服务器等,这种兼容性让用户可以在不同平台之间轻松的迁移应用。
- 更简单的更新管理。
使用Dockerfile,只需要小小的配置修改,就可以替代以往的大量的更新工作。并且所有修改都是以增量的方式进行分发和更新,从而实现自动化和高效的容器管理。
3.虚拟化与docker
虚拟化定义:虚拟化是一种资源管理技术,是将计算机的各种实体资源,如服务器、网络、内存及存储等,予以抽象、转换后呈现出来,打破实体结构间的不可切割的障碍,使用户可以比原本的配置更好的方式来应用这些资源。这些资源的新虚拟部分是不受现有资源的架设方式,地域或物理配置所限制。一般所指的虚拟化资源包括计算能力和数据存储。
系统虚拟化,Hypervisor Virtualization,全虚拟化。在 Host 中通过 Hypervisor 层实现安装多个 GuestOS,每个 GuestOS 都有自己的内核,和主机的内核不同,GuestOS 之间完全隔离。
容器虚拟化,Operating System Virtualization ,使用 Linux 内核中的 namespaces 和 cgroups 实现进程组之间的隔离。是用内核技术实现的隔离,所以它是一个共享内核的虚拟化技术。
容器虚拟化没有 GuestOS,使用 Docker 时下载的镜像,只是为运行 App 提供的一个依赖的环境,是一个删减版本的系统镜像。一般情况下系统虚拟化没有容器虚拟化的运行效率高,但是系统安全性高很多。
优越性:
你在一台机器可以开10个虚拟机,如果用docker可以开100个容器,就是这么霸气
4.docker官网注册
注册一个docker账号:https://hub.docker.com/
完成注册,我用的qq邮箱,等了10分钟才收到。
收到后激活邮箱,进行登录
登录完毕
二、核心概念和安装
1.环境介绍
操作系统:CentOS7 7.6 X64
docker版本:18.06.1-ce
要求: 内核版本最低为3.10
查看当前内核版本: uname –r
更改网卡配置:vim /etc/sysconfig/network-scripts/ifcfg-enp0s3
,ONBOOT="yes"
2.通过yum方式安装docker
新增一般用户,并加入到sudo组,以下命令均使用一般用户执行
第一步:更新yum源: sudo yum update
第二步:增加docker的yum源
# sudo vim /etc/yum.repos.d/docker.repo
[dockerrepo]
name=Docker Repository
baseurl=https://yum.dockerproject.org/repo/main/centos/$releasever/
enabled=1
gpgcheck=1
gpgkey=https://yum.dockerproject.org/gpg
第三步:通过yum安装docker:sudo yum install docker
第四步:启动docker服务:sudo systemctl start docker.service
第五步:查看版本信息,通过测试用例验证docker是否安装成功:docker version
测试:sudo docker run hello-world
第六步:docker配置
设置docker开机启动:sudo chkconfig docker on
docker卸载
查看安装包:sudo yum list installed | grepdocker
移除安装包:sudo yum -y remove docker.x86_64
清除所有docker依赖文件:sudo rm -rf /var/lib/docker
3.Docker的核心概念
3.1 Docker核心概念之镜像
Docker 镜像就是一个只读的模板。
例如:一个镜像可以包含一个完整的 centos操作系统环境,里面仅安装了 Apache 或用户需要的其它应用程序。
镜像可以用来创建 Docker 容器。
创建Docker镜像有几种方式,多数是在一个现有镜像基础上创建新镜像,因为几乎你需要的任何东西都有了公共镜像,包括所有主流Linux发行版,你应该不会找不到你需要的镜像。不过,就算你想从头构建一个镜像,也有好几种方法。
要创建一个镜像,你可以拿一个镜像,对它进行修改来创建它的子镜像 。
3.2 Docker核心概念之容器
Docker 利用容器来运行应用。
容器是从镜像创建的运行实例。它可以被启动、开始、停止、删除。每个容器都是相互隔离的、保证安全的平台。
可以把容器看做是一个简易版的 Linux 环境(包括root用户权限、进程空间、用户空间和网络空间等)和运行在其中的应用程序。
注:镜像是只读的,容器在启动的时候创建一层可写层作为最上层。
3.3 Docker核心概念之仓库
仓库是集中存放镜像文件的场所。
有时候会把仓库和仓库注册服务器(Registry)混为一谈,并不严格区分。实际上,仓库注册服务器上往往存放着多个仓库,每个仓库中又包含了多个镜像,每个镜像有不同的标签(tag)。Centos的6.0和7.0就是tag。
三、镜像的常用操作
1.获取镜像
命令:
docker pull <域名>/<namespace>/<repo>:<tag>
比如:sudo docker pull centos
说明:
镜像是Docker运行容器的前提。
用户可以使用docker pull 命令从网络上下载镜像。对于镜像来说,如果不显式地指定tag,则默认会选择latest标签,即下载仓库中最新版本的镜像。
默认是从docker官方下载的。只有docker官方的可以不需要增加命名空间直接进行下载。
2.查看镜像列表
命令:
docker images
说明:
使用docker images命令可以列出本地主机上已有的镜像。
信息含义:来自于哪个仓库、镜像的标签信息、镜像的ID号(唯一)、创建时间、镜像大小。
3.查看镜像信息
命令:
docker inspect <image_id>
说明:
docker inspect命令返回的是一个JSON的格式消息,如果我们只要其中的一项内容时,可以通过-f参数来指定。Image_id通常可以使用该镜像ID的前若干个字符组成的可区分字符串来替代完成的ID。
sudo docker inspect -f {{.DockerVersion}} image_id
# DockerVersion前面有一个点号,查询指定的内容
4.查找镜像
命令:
docker search <image_name>
说明:
使用docker search命令可以搜索远端仓库中共享的镜像,默认搜索Docker hub官方仓库中的镜像。
5.删除镜像
命令:
docker rmi <image>:<tag>
说明:
使用docker rmi
命令可以删除镜像,其中image可以为标签或ID。
注意:
-
当同一个镜像拥有多个标签,
docker rmi
只是删除该镜像多个标签中的指定标签而已,而不影响镜像文件。 -
当有该镜像创建的容器存在时,镜像文件默认是无法被删除的。
-
如果一个镜像就有一个tag的话,删除tag就删除了镜像的本身。
如果镜像里面有容器正在运行,删除镜像的话,会提示error,系统默认是不允许删除的,如果强制删除需要加入-f
操作,但是docker是不建议这么操作的,因为你删除了镜像其实容器并未删除,直接导致容器找不到镜像,这样会比较混乱。
一个镜像做一个tag:sudo docker tag image_id image:tag
执行删除tag操作:sudo docker rmi image:tag
运行一个镜像里面的容器:$ sudo docker run centos echo 'Docker hahaha'
查看运行中的容器:sudo docker ps -a
6.创建镜像
命令:
docker commit <options> <container_id><repository:tag>
参数说明:
-a , --author : 作者信息
-m , --meassage : 提交消息
-p , --pause=true : 提交时暂停容器运行
说明:
基于已有的镜像的容器的创建。
例子:以centos为例子创建
运行centos,-ti把容器内标准绑定到终端并运行bash,这样开跟传统的linux操作系统没什么两样,现在我们直接在容器内运行。这个内部系统都是极简的只保留我们的一些系统的运行参数,里面很多vi命令可能都是没有的。
$ sudo docker run -ti centos
[root@158183a8ae93 /]# echo '1111' > 1.txt
[root@158183a8ae93 /]# exit
退出容器exit。
容器创建成镜像的方法:
通过某个容器d1d6706627f1 创建对应的镜像,有点类似git。注意,是根据容器ID创建的,可以使用docker pa -a
事先查看容器ID
命令:docker commit -a 'author' -m 'message' container_id image_name
sudo docker commit -a 'Sandu' -m 'create a docker version' 158183a8ae93 centos11/test
7.迁出镜像
命令:
docker save -o <image>.tar <image>:<tag>
参数说明:
-o:设置存储压缩后的文件名称
说明:
可以使用docker save命令来迁出镜像,其中image可以为标签或ID。
8.载入镜像
命令:
docker load --input <image>.tar
`
说明:
使用docker load命令可以载入镜像,其中image可以为标签或ID。这将导入镜像及相关的元数据信息(包括标签等),可以使用docker images
命令进行查看。可以先删除之前的镜像然后再导入,或者在一台新机器上部署docker环境后再导入
默认载入的镜像没有镜像名称和tag,使用下面的命令创建:sudo docker tag image_id image_name
,tag自动为latest
9.上传镜像
命令:
docker push <域名>/<namespace>/<repo>:<tag>
说明:
可以使用docker push命令上传镜像到仓库,默认上传到DockerHub官方仓库(需要登录)。
# 登陆到docker官网
$ sudo docker login
# 输入账号密码,提示:Login Succeeded
# 然后开始上传镜像,注意:image_name的/前部分名称要与官网注册的名称一致,否则提示:denied: requested access to the resource is denied
# 可以使用tag方式复制一份镜像并重命名的方式来上传镜像
# sudo docker tag image_id xxxx/iamge_name # xxxx要与在官网上注册的Docker ID保持一致
$ sudo docker push image_name
四、容器的常用操作
1.创建容器
Docker的容器十分轻量级,用户可以随时创建或删除容器。
新建容器:docker create
Example:docker create –it centos
说明:使用docker create命令创建的容器处于停止状态,可以使用docker start
命令启动它。
$ sudo docker create -it centos
$ sudo docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
00e0a9ee7fe2 centos "/bin/bash" 8 seconds ago Created affectionate_mahavira
新建并启动容器:``docker run`
Example: docker run centos /bin/echo “Hello World”
说明: 等价于先执行docker create
命令,再执行docker start
命令。
docker run 背后的故事:
-
1 检查本地是否存在制定的镜像,不存在就从公有仓库下载。
-
2 利用本地镜像创建并启动一个容器。
-
3 分配一个文件系统,并在只读的镜像层外面挂载一层可读写层。
-
4 从宿主机配置的网桥接口桥接一个虚拟接口到容器中去。
-
5 从地址池配置一个IP地址给容器。
-
6 执行用户的指定的用户程序。
-
7 执行完毕后容器被终止。
一条简单的命令:
docker run -i –t centos /bin/bash
-
-t : 让docker分配一个伪终端并绑定到容器的标准输入上。
-
-i : 让容器的标准输入保持打开。
在交互模式下,用户可以通过所创建的终端来输入命令,exit命令退出容器。
退出后,容器自动处于终止状态。
守护台运行:
更多的时候,需要让Docker容器运行在后台以守护态(daemonized)形式运行。用户可以通过添加-d参数来实现。
Example:
docker run -d centos /bin/bash -c "while true;do echo hello world;sleep 1;done"
补充:
查看日志: docker logs <container_id>
docker logs –f <container_id>
动态的查看日志,类似查看tomcat的日志一样
2.终止容器
可以使用docker stop
命令来终止一个运行中的容器。
docker stop <container_id>
注意:当容器中的应用终结时,容器也会自动停止。
查看终止的容器:docker ps -a
查看运行的容器:docker ps
重新启动容器:docker start <container_id>
3.进入容器
在使用-d参数时,容器启动后会进入后台,用户无法看到容器中的信息。
docker exec <options> <container_id> <command>
Exec可以直接在容器内部运行命令。前提是容器正在运行。
进入容器:
docker exec -i –t <container_id> bash
区别:
-
run 运行一个容器后,进入容器的话,exit退出后,容器也直接退出
-
exec 进入容器后,exit退出后,容器不退出仍在后台运行
4.删除容器
可以使用docker rm
命令删除终止状态的容器。
docker rm image_name|image_id
如果删除正在运行的容器,需要停止容器然后进行删除。
不管容器是否运行,可以使用docker rm –f
命令进行删除。
5.导入和导出容器
导出容器是指导出一个已经创建的容器到一个文件,不管容器是否处于运行状态。可以使用docker export
命令。
docker export <container_id>
Example:
docker export container_id > test.tar
sudo docker export 7adfb980d640 > test_contain_id.tar
导出的文件又可以使用docker import
命令导入,成为镜像。
Example:
cat test_contain_id.tar | docker import - image_name:latest
注意:不知为啥,一般用户无法导入,需要使用root用户才可以导入成功
五、仓库
1.Docker Hub
仓库是集中存放镜像的地方。
目前Docker官方仓库维护了一个公共仓库https://hub.docker.com,其中已经包括15000多个的镜像。
大部分需求都可以通过在Docker Hub中直接下来镜像来实现。
登陆:
可以通过执行docker login
命令来输入用户名、密码和邮箱来完成注册登录。
基本操作
用户无需登录可以通过 docker search
命令来查找官方仓库中的镜像,并利用docker pull
下载到本地,可以通过docker push
命令将本地镜像推送到docker hub。
先tag一下复制一个镜像,然后把镜像push到服务器上。
2.创建和使用私有仓库
使用registry镜像创建私有仓库
可以通过docker官方提供的registry镜像来搭建一套本地私有仓库。
镜像地址:https://hub.docker.com/_/registry/
命令:
docker run -e SEARCH_BACKEND=sqlalchemy -e SQLALCHEMY_INDEX_DATABASE=sqlite:////tmp/docker-registry.db -d --name registry -p 5000:5000 registry
命令参数:
-
-e设定环境变量
-
-d从后台启动的方式镜像启动
-
-name 启动的容器起个名字
-
-p 暴露端口,容器内部的5000绑定到宿主机的5000端口上。
-
registry镜像本身
-
SEARCH_BACKEND=sqlalchemy默认索引是可以查询的
参考地址:
https://github.com/docker/docker-registry#search-engine-options
https://hub.docker.com/_/registry/
# 1. 先配置,提前解决后续出现的问题:http: server gave HTTP response to HTTPS client
[sandu@bogon ~]$ sudo vim /etc/doker/daemon.json # 没有该文件的话就创建一个
{ "insecure-registries":["192.168.0.192:5000"] } # ip为本机的ip,5000端口为后续使用的端口
# 重启docker服务
[sandu@bogon ~]$ sudo systemctl daemon-reload
[sandu@bogon ~]$ sudo systemctl restart docker.service
# 2. 登陆docker
[sandu@bogon ~]$ sudo docker login
# 3.拉取私有仓库镜像
[sandu@bogon ~]$ sudo docker run -e SEARCH_BACKEND=sqlalchemy -e SQLALCHEMY_INDEX_DATABASE=sqlite:////tmp/docker-registry.db -d --name registry -p 5000:5000 registry
[sudo] password for sandu:
Unable to find image 'registry:latest' locally
Trying to pull repository docker.io/library/registry ...
latest: Pulling from docker.io/library/registry
c87736221ed0: Pull complete
1cc8e0bb44df: Pull complete
54d33bcb37f5: Pull complete
e8afc091c171: Pull complete
b4541f6d3db6: Pull complete
Digest: sha256:8004747f1e8cd820a148fb7499d71a76d45ff66bac6a29129bfdbfdc0154d146
Status: Downloaded newer image for docker.io/registry:latest
1cec256c7e63bb6b29cbeb7ae1b3b25fc53fbb86122b950eee788f553ce14619
# 查看当前运行的容器
[sandu@bogon ~]$ sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
630bf936586d registry "/entrypoint.sh /e..." 9 minutes ago Up 9 minutes 0.0.0.0:5000->5000/tcp registry
# 查看现有镜像
[sandu@bogon ~]$ sudo docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
docker.io/centos latest 9f38484d220f 4 months ago 202 MB
docker.io/registry latest f32a97de94e1 5 months ago 25.8 MB
# 4.拉取一个公共镜像,修改后打算上传到私有仓库,需要给该镜像重新赋值一个tag
[sandu@bogon ~]$ sudo docker tag docker.io/centos 192.168.0.192:5000/sanduzxcvbnm/test2_registry
# 注意:前面的参数是打算上传到私有仓库的镜像,后面那个是重新赋值的tag,最前面的是私有仓库地址,中间的是在docker官网注册的用户名,后者是镜像名
[sandu@bogon ~]$ sudo docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
192.168.0.192:5000/sanduzxcvbnm/test2_registry latest 9f38484d220f 5 months ago 202 MB
docker.io/centos latest 9f38484d220f 5 months ago 202 MB
docker.io/registry latest f32a97de94e1 5 months ago 25.8 MB
# 5.上传镜像到私有仓库
[sandu@bogon ~]$ sudo docker push 192.168.0.192:5000/sanduzxcvbnm/test2_registry
3.仓库加速服务
加速下载官方镜像。
推荐服务:https://dashboard.daocloud.io/
点击加速器:https://dashboard.daocloud.io/mirror
4.仓库管理
Registry Web UI 用于镜像的查询,删除。
镜像地址:https://hub.docker.com/r/atcol/docker-registry-ui/
# 拉取管理仓库的web镜像,把私有仓库绑定到管理仓库web并启动
[sandu@bogon ~]$ sudo docker run -d --name registry_ui -p 8080:8080 -e REG1=http://192.168.0.192:5000/v1/ atcol/docker-registry-ui
# 问题
界面上虽然能看到自己创建的私有仓库信息,但是界面提示:ping faild
查看日志:docker logs -f registry_ui,报错信息如下:
2019-08-12 03:24:00,187 [http-nio-8080-exec-5] ERROR web.RepositoryService - Failed to ping http://192.168.0.192:5000/v1/_ping: 404 : Not Found
此问题留待以后解决,初步判断是需要给私有仓库添加认证信息
六、数据管理
1.数据卷
数据卷是一个可供容器使用的特殊目录,有如下特性:
-
数据卷可以在容器之间共享和重用
-
数据卷修改会立即生效
-
数据卷的更新不会影响镜像
-
如果有容器使用数据卷,该卷会一直存在
准备工作:
创建一个目录,并在目录里面创建文件,文件内写入内容。
[root@bogon ~]# cd /tmp/
[root@bogon tmp]# mkdir webapp
[root@bogon tmp]# cd webapp/
[root@bogon webapp]# echo '数据卷' > 1.txt
[root@bogon webapp]# cat 1.txt
数据卷
[root@bogon webapp]#
1.1在容器内创建数据卷
在使用docker run的命令时,使用 -v 标记可以在容器内创建一个数据卷,并且可以指定挂在一个本地已有的目录到容器中作为数据卷:
创建启动app1容器并挂载数据卷,注意,此时是在tmp目录下进行的操作
echo ${pwd}
命令标识当前目录
[root@bogon tmp]# docker run -d --name app1 -it -v ${pwd}/webapp:/root/webapp centos bash
通过目录跟容器内建立了一层关系,数据卷发生变化后,容器内和容器外都会随之发生改变。例如容器挂载一个文件,当容器挂了后,文件不会丢失。
注意:默认挂载的数据卷的权限是rw(可读写),如果要求ro(只读),则需要加上对应的ro参数,命令可改为:
docker run -d --name app1 -it -v ${pwd}/webapp:/root/webapp:ro centos bash
# 创建启动app1容器并挂载数据卷,前者/tmp/webapp是本机路径,后者/tmp/webapp1是容器路径
[root@bogon webapp]# docker run -d -it --name app1 -v /tmp/webapp:/tmp/webapp1 centos bash
# 进入容器找到/tmp目录可查看到已挂载的数据卷
[root@bogon webapp]# docker exec -it app1 bash
[root@11755ef11dc1 /]# cd /tmp/
[root@11755ef11dc1 tmp]# ll
total 4
-rwx------. 1 root root 836 Mar 5 17:36 ks-script-eC059Y
drwxr-xr-x. 2 root root 32 Aug 13 06:30 webapp1
-rw-------. 1 root root 0 Mar 5 17:34 yum.log
# 数据卷目录与容器内目录有映射关系,所以不管是在容器内部修改数据卷还是在外部修改数据卷,相对应的数据卷都会发生改变。
# 在容器内修改文件数据后,exit退出容器,进入本机路径查看文件,会发现文件也发生了变化.
# 只读权限是无法写入数据的
2.数据卷容器
数据卷容器用于用户需要在容器间共享一些持续更新的数据,数据卷容器专门提供数据卷供其它容器挂载使用。
2.1 创建数据卷容器
Example:
创建数据卷容器db1
docker run -d --name db1 -v /dbdata -ti centos bash
创建容器db2与db1共享dbdata的数据
docker run -d --name db2 --volumes-from db1 -ti centos bash
# 创建数据卷容器db1
[root@bogon tmp]# docker run -d --name db1 -v /tmp/dbdata/ -it centos bash
# 创建数据卷容器db2,使用db1的数据卷
[root@bogon tmp]# docker run -d --name db2 --volumes-from db1 -it centos bash
# 在容器db1和容器db2任意一个容器修改/tmp/dbdata/的内容,在两个容器内均生效
2.2 数据卷容器的删除
如果删除了挂载的容器,数据卷并不会被自动删除,如果要删除一个数据卷,必须在删除最后一个还挂载它的容器时显示使用docker rm -v 命令指定同时删除关联的容器。可以利用数据卷容器对其中的数据卷进行备份、恢复,以实现数据的迁移。
2.3 数据卷容器的备份
使用下面的命令来备份dbdata数据卷容器内的数据卷:
docker run --volumes-from /tmp/dbdata -v ${PWD}:/backup --name worker centos \tar cvf /backup/backup.tar /tmp/dbdata
说明:
利用centos镜像创建一个容器worker。
使用``--volumes-from /tmp/dbdata`参数来让worker容器挂载dbdata的数据卷。
使用${pwd}:/backup
参数来挂载本地目录到worker容器的/backup目录。
worker启动后,使用tar命令将/tmp/dbdata下的内容备份为容器内的/backup/backup.tar。
2.4 数据卷容器的恢复
如果恢复数据到一个容器,可以参照下面的操作。首先创建一个带有数据卷的容器dbdata2:
docker run -d -v /dbdata --name dbdata2 centos /bin/bash`
然后创建另一个新的容器,挂载dbdata2的容器,并使用tar命令解压备份文件到挂载的容器卷中即可:
docker run --volumes-fromd bdata2 -v ${pwd}:/backup centos tar xvf /backup/backup.tar
七、网络
1.容器对外服务
当容器内运行一些网络应用,要让外部访问这些应用时,可以通过 -P 或 -p 参数来指定端口映射。
使用 -P 映射时,Docker会随机映射一个49000 ~49900 的端口至容器内部开放的端口:
docker run -d -P --name mysql mysql:5.6
通过docker ps
可以看到端口映射关系。
可以通过映射在宿主机的端口来访问对应容器内的服务。
映射到指定宿主机的端口:
# 从官网拉取并运行MySQL5.6镜像,并设置镜像内的MySQL连接密码
docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:5.6
# -e 是环境变量的意思 运行容器内的环境变量设置mysql的密码
# 默认使用宿主机的3306端口
映射到指定地址的指定端口,为例:
docker run -d -p 3306:3306 --name -e MYSQL_ROOT_PASSWORD=my-secret-pw mysql mysql:5.6
若不加上-e
参数,则会报错:
error: database is uninitialized and password option is not specified You need to specify one of MYSQL_ROOT_PASSWORD, MYSQL_ALLOW_EMPTY_PASSWORD and MYSQL_RANDOM_ROOT_PASSWORD
[root@bogon log]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
9f298b7aeb6e mysql:5.6 "docker-entrypoint..." 3 seconds ago Up 2 seconds 0.0.0.0:3306->3306/tcp mysql
# 0.0.0.0表示任意主机均能访问
外部访问宿主机的3306直接映射到容器的3306连接到数据库
映射到指定地址的指定端口,以127.0.0.1为例:
docker run -d -p 127.0.0.1:3306:3306 -e MYSQL_ROOT_PASSWORD=my-secret-pw --name mysql mysql:5.6
[root@bogon log]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
082f503397da mysql:5.6 "docker-entrypoint..." 3 seconds ago Up 2 seconds 127.0.0.1:3306->3306/tcp quirky_franklin
# 127.0.0.1 表示仅本机才能访问,没有使用--name指定容器名则随机生成一个
映射到指定地址的任意端口,以127.0.0.1为例:
docker run -d -p 127.0.0.1::3306 -e MYSQL_ROOT_PASSWORD=my-secret-pw --name mysqlmysql:5.6
[root@bogon log]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
29293afe0d7a mysql:5.6 "docker-entrypoint..." 4 seconds ago Up 3 seconds 127.0.0.1:32768->3306/tcp unruffled_curran
# 宿主机没有指定端口,则随机使用一个端口跟容器3306端口做映射
查看映射端口配置:
docker port mysql 3306
[root@bogon log]# docker port 29293afe0d7a
3306/tcp -> 127.0.0.1:32768
2.容器间相互通信
通过映射宿主机的端口实现容器的互联。
使用--link
参数可以让容器之间安全的进行交互。
创建一个数据库容器:
docker run -d -e MYSQL_ROOT_PASSWORD=my-secret-pw --name mysqldb mysql:5.6
创建一个web容器并和数据库容器建立连接:
docker run -d --name Webapp -p 8000:8080 --link mysqldb:MySQL tomcat
上边的MySQL别名就类似dns解析的方式,我给这个容器起了个别名叫MySQL,我就通过这个别名就可以找到对应的这个mysqldb容器
mysqldb容器和web容器建立互联关系。
--link
参数的格式为--link name:alias
,其中name是要连接的容器名称,alias是这个连接的别名。
[root@bogon log]# docker run -d -e MYSQL_ROOT_PASSWORD=my-secret-pw --name mysqldb mysql:5.6
5978df27095f87193bf6dbffd5cf7c1e315b19129687c4409757b83923a70c02
[root@bogon log]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5978df27095f mysql:5.6 "docker-entrypoint..." 5 seconds ago Up 4 seconds 3306/tcp mysqldb
[root@bogon log]# docker run -d --name webapp -p 8000:8080 --link mysqldb:MySQL tomcat
Unable to find image 'tomcat:latest' locally
Trying to pull repository docker.io/library/tomcat ...
latest: Pulling from docker.io/library/tomcat
9cc2ad81d40d: Pull complete
8e391ba3712a: Pull complete
Digest: sha256:ddb9336dcd0ff66874db84880d58f6571bfa737cf6390bc38a66d1f78a857be6
Status: Downloaded newer image for docker.io/tomcat:latest
690b944739532e1ce55dfe49b5e3b24ddd5a13f8030d384c975f87631a8a5056
[root@bogon log]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
690b94473953 tomcat "catalina.sh run" 3 seconds ago Up 2 seconds 0.0.0.0:8000->8080/tcp webapp
5978df27095f mysql:5.6 "docker-entrypoint..." About a minute ago Up About a minute 3306/tcp mysqldb
[root@bogon log]# docker exec -it webapp bash
root@690b94473953:/usr/local/tomcat# ping MySQL
PING MySQL (172.17.0.2) 56(84) bytes of data.
64 bytes from MySQL (172.17.0.2): icmp_seq=1 ttl=64 time=0.119 ms
64 bytes from MySQL (172.17.0.2): icmp_seq=2 ttl=64 time=0.078 ms
^Z
[1]+ Stopped ping MySQL
可以使用docker ps(PORT字段)来查看容器的连接。
Docker在两个容器之间创建了安全隧道,而且不用映射它们的端口到宿主机上。在启动mysqldb的时候并没有使用-p和-P标记,从而避免的了暴露数据库的端口到外部的网络上。
link就是容器直接互相通信的
Docker通过两种方式为容器公开连接信息:
1 环境变量:
使用env命令来查看。
EX:docker run --rm --name test --link dblink:dblink ubuntu env
2 更新/etc/hosts文件
查看/etc/hosts文件。
八 、Dockerfile
1. 利用Dockerfile创建镜像
什么是Dockerfile?
定义:Dockerfile是一个文本格式的配置文件,用户可以使用Dockerfile快速创建自定义镜像。
基本结构:
Dockerfile由一行行的命令语句组成。并且支持以#开头的注释行。
一般Dockerfile分为四个部分:基础镜像信息、维护者信息、镜像操作指令和容器启动时的指令。
Dockerfile示例:
#This is a Dockerfile
#Author:liming
#第一行必须指定基础镜像
FROM ubuntu
#维护者信息
MAINTAINER 394498036@qq.com
#镜像的操作指令
RUN apt-get update
RUN apt-getinstall -y nginx
RUN echo “\ndaemonoff:” >> /etc/nginx/nginx.conf
#容器启动时的指令
CMD /usr/sbin/nginx
创建命令:
docker build –t=“<镜像名称>” .
注意:执行此命令要和Dockerfile在同级目录,文件名称必须为Dockerfile。命令后面的”.”表示在当前目录下执行。
2.Dockerfile指令集
1 FROM
格式为 FROM 或:
第一条指令必须为FROM指令,用于指定基础镜像。
2 MAINTAINER
格式为 MAINTAINER
3 RUN
格式为 RUN
4 EXPOSE
格式为 EXPOSE
5 ENV
格式为 ENV
指定一个环境变量,可以被后续的RUN引用,并且在容器中记录该环境变量。
6 ADD
格式为 ADD
该命令将复制指定的
7 VOLUME
格式为 VOLUME [path]。
创建一个可以从本地主机或其他容器挂载点,一般用来存放需要保持的数据。
8 USER
格式为 USER
指定运行容器时的用户名,后续的RUN也会指定该用户。
9 WORKDIR
格式为 WORKDIR <work_path>。
指定工作空间,运行完WORKDIR后,后续执行的RUN、CMD、ENTRYPOINT都会在此目录下执行。
10 COPY
格式为 COPY
复制本地主机的
当使用本地目录为源目录时,推荐使用COPY。
11 CMD
推荐格式为 CMD [“executable”,”param1”,”param2”] 。
作为ENTRYPOINT的默认参数为 CMD[”param1”,”param2”]。
指定容器的启动命令,每个Dockerfile只能有一条CMD命令,如果指定多条,只有最后一条会执行。
用户启动容器时指定运行命令,会覆盖掉Dockerfile中的CMD命令。
12 ENTRYPOINT
格式为 ENTRYPOINT [“executable”,”param1”,”param2”]。
配置容器启动后的命令,可被docker run提供的--entrypoint参数覆盖。
每个Dockerfile只能有一条ENTRYPOINT命令,如果指定多条,只有最后一条会执行。
3.容器内安装工具的方法
yum 或者apt-get
4.Dockerfile最佳实践
1 错误定位
每个Dockerfile的指令可以生成新的一层镜像,如果通过Dockerfile创建镜像出错,可以根据出错所在步骤的上一层启动容器,然后手工执行出错层的命令,以达到调试目的。
2 好的使用习惯
1、使用缓存
Dockerfile的每条指令都会将结果提交为新的镜像,下一个指令将会基于上一步指令的镜像的基础上构建,如果一个镜像存在相同的父镜像和指令(除了ADD),Docker将会使用镜像而不是执行该指令,即缓存。
为了有效地利用缓存,你需要保持你的Dockerfile一致,并且尽量在末尾修改。我所有的Dockerfile的前五行都是这样的:
FROM ubuntu
MAINTAINER Michael Crosby <michael@crosbymichael.com>
RUN echo "deb http://archive.ubuntu.com/ubuntu precise main universe" > /etc/apt/sources.list
RUN apt-get update
RUN apt-get upgrade -y
更改MAINTAINER指令会使Docker强制执行RUN指令来更新apt,而不是使用缓存。
所以,我们应该使用常用且不变的Dockerfile开始(译者注:上面的例子)指令来利用缓存。
2、使用标签
除非你正在用Docker做实验,否则你应当通过-t选项来docker build新的镜像以便于标记构建的镜像。一个简单的可读标签将帮助你管理每个创建的镜像。
docker build -t="crosbymichael/sentry" .
注意,始终通过-t标记来构建镜像。
3、公开端口
两个Docker的核心概念是可重复和可移植。镜像应该可以运行在任何主机上并且运行尽可能多的次数。在Dockerfile中你有能力映射私有和公有端口,但是你永远不要通过Dockerfile映射公有端口。通过映射公有端口到主机上,你将只能运行一个容器化应用程序实例。(译者注:运行多个端口不就冲突啦)
#private and public mapping
EXPOSE 80:8080
#private only
EXPOSE 80
如果镜像的使用者关心容器公有映射了哪个公有端口,他们可以在运行镜像时通过-p参数设置,否则,Docker会自动为容器分配端口。
切勿在Dockerfile映射公有端口。
4、CMD与ENTRYPOINT的语法
CMD和ENTRYPOINT指令都非常简单,但它们都有一个隐藏的容易出错的“功能”,如果你不知道的话可能会在这里踩坑,这些指令支持两种不同的语法。
CMD /bin/echo
#or
CMD ["/bin/echo"]
这看起来好像没什么问题,但仔细一看其实两种方式差距很大。如果你使用第二个语法:CMD(或ENTRYPOINT)是一个数组,它执行的命令完全像你期望的那样。如果使用第一种语法,Docker会在你的命令前面加上/bin/sh -c,我记得一直都是这样。
如果你不知道Docker修改了CMD命令,在命令前加上/bin/sh -c可能会导致一些意想不到的问题以及难以理解的功能。因此,在使用这两个指令时你应当使用数组语法,因为数组语法会确切地执行你打算执行的命令。
使用CMD和ENTRYPOINT时,请务必使用数组语法。
5、CMD和ENTRYPOINT 结合使用更好
docker run命令中的参数都会传递给ENTRYPOINT指令,而不用担心它被覆盖(跟CMD不同)。当与CMD一起使用时ENTRYPOINT的表现会更好。让我们来研究一下我的Rethinkdb Dockerfile,看看如何使用它。
#Dockerfile for Rethinkdb
#http://www.rethinkdb.com/
FROM ubuntu
MAINTAINER Michael Crosby <michael@crosbymichael.com>
RUN echo "deb http://archive.ubuntu.com/ubuntu precise main universe" > /etc/apt/sources.list
RUN apt-get update
RUN apt-get upgrade -y
RUN apt-get install -y python-software-properties
RUN add-apt-repository ppa:rethinkdb/ppa
RUN apt-get update
RUN apt-get install -y rethinkdb
#Rethinkdb process
EXPOSE 28015
#Rethinkdb admin console
EXPOSE 8080
#Create the /rethinkdb_data dir structure
RUN /usr/bin/rethinkdb create
ENTRYPOINT ["/usr/bin/rethinkdb"]
CMD ["--help"]
这是Docker化Rethinkdb的所有配置文件。在开始我们有标准的5行来确保基础镜像是最新的、端口的公开等。当ENTRYPOINT指令出现时,我们知道每次运行该镜像,在docker run过程中传递的所有参数将成为ENTRYPOINT(/usr/bin/rethinkdb)的参数。
在Dockerfile中我还设置了一个默认CMD参数--help。这样做是为了docker run期间如果没有参数的传递,rethinkdb将会给用户显示默认的帮助文档。这是你所期望的与rethinkdb交互相同的功能。
docker run crosbymichael/rethinkdb
输出
Running 'rethinkdb' will create a new data directory or use an existing one,
and serve as a RethinkDB cluster node.
File path options:
-d [ --directory ] path specify directory to store data and metadata
--io-threads n how many simultaneous I/O operations can happen
at the same time
Machine name options:
-n [ --machine-name ] arg the name for this machine (as will appear in
the metadata). If not specified, it will be
randomly chosen from a short list of names.
Network options:
--bind {all | addr} add the address of a local interface to listen
on when accepting connections; loopback
addresses are enabled by default
--cluster-port port port for receiving connections from other nodes
--driver-port port port for rethinkdb protocol client drivers
-o [ --port-offset ] offset all ports used locally will have this value
added
-j [ --join ] host:port host and port of a rethinkdb node to connect to
.................
现在,让我们带上--bind all参数来运行容器。
docker run crosbymichael/rethinkdb --bind all
输出
info: Running rethinkdb 1.7.1-0ubuntu1~precise (GCC 4.6.3)...
info: Running on Linux 3.2.0-45-virtual x86_64
info: Loading data from directory /rethinkdb_data
warn: Could not turn off filesystem caching for database file: "/rethinkdb_data/metadata" (Is the file located on a filesystem that doesn't support direct I/O (e.g. some encrypted or journaled file systems)?) This can cause performance problems.
warn: Could not turn off filesystem caching for database file: "/rethinkdb_data/auth_metadata" (Is the file located on a filesystem that doesn't support direct I/O (e.g. some encrypted or journaled file systems)?) This can cause performance problems.
info: Listening for intracluster connections on port 29015
info: Listening for client driver connections on port 28015
info: Listening for administrative HTTP connections on port 8080
info: Listening on addresses: 127.0.0.1, 172.16.42.13
info: Server ready
info: Someone asked for the nonwhitelisted file /js/handlebars.runtime-1.0.0.beta.6.js, if this should be accessible add it to the whitelist.
就这样,一个全面的可以访问db和管理控制台的Rethinkdb实例就运行起来了,你可以用与镜像交互一样的方式来与其交互。虽然简单小巧但它的功能非常强大。
CMD和ENTRYPOINT 结合在一起使用更好。
我希望这篇文章可以帮助你使用Dockerfiles以及构建镜像。Dockerfile是Docker的重要一部分,无论你是构建或是使用镜像,它都非常简单而且使用方便。我打算投入更多的时间来提供一个完整的、功能强大但简单的解决方案来使用Dockerfile构建Docker镜像。
1、不要开机初始化
容器模型是进程而不是机器。如果你认为你需要开机初始化,那么你就错了。
2、可信任构建
即使你不喜欢这个题目但它是很棒的一个功能。我把大部分 GitHub 仓库添加到可信任构建,因此当我提交一个新镜像之后不久,就在等待索引。另外,我不必再创建单独的 Dockerfile 仓库与他人分享,它们都在同一个地方。
请记住,这不是你尝试新东西的试验场。在你推送之前,请在本地先构建一下。Docker 可以确保你在本地的构建和运行,与你推送到任何地方的构建和运行是一样的。本地开发和测试、提交和推送、以及等待索引上的官方镜像都是建立在可信任构建的基础之上的。
3、不要在构建中升级版本
更新将发生在基础镜像里,你不需要在你的容器内来apt-get upgrade更新。因为在隔离情况下,如果更新时试图修改 init 或改变容器内的设备,更新可能会经常失败。它还可能会产生不一致的镜像,因为你不再有你的应用程序该如何运行以及包含在镜像中依赖的哪种版本的正确源文件。
如果基础镜像需要安全更新,那么让上游的知道,让他们给大家更新,并确保你再次构建的一致性。
4、使用小型基础镜像
有些镜像比其他的更臃肿。我建议使用debian:jessie作为你的基础镜像。如果你熟悉Ubuntu,你将发现一个更轻量和巧妙的自制 debian,它足够小并且没有包含任何不需要的包。
5、使用特定的标签
对于你的基础镜像这是非常重要的。Dockerfile 中FROM应始终包含依赖的基础镜像的完整仓库名和标签。比如说FROM debian:jessie而不仅仅是FROM debian。
6、常见指令组合
您的apt-get update应该与apt-get install组合。此外,你应该采取\的优势使用多行来进行安装。
#Dockerfile for https://index.docker.io/u/crosbymichael/python/
FROM debian:jessie
RUN apt-get update && apt-get install -y \
git \
libxml2-dev \
python \
build-essential \
make \
gcc \
python-dev \
locales \
python-pip
RUN dpkg-reconfigure locales && \
locale-gen C.UTF-8 && \
/usr/sbin/update-locale LANG=C.UTF-8
ENV LC_ALL C.UTF-8
谨记层和缓存都是不错的。不要害怕过多的层,因为缓存是大救星。当然,你应当尽量使用上游的包。
7、使用自己的基础镜像
我不是在谈论运行 debbootstrap 来制作自己的 debian。你不是 tianon(Tianon Gravi),没有人想要你认为别人需要你的 500mb 的狗屎垃圾基础镜像。我说的是,如果你要运行 python 应用程序需要有一个python基础镜像。前面示例中用于构建 crosbymichael/python 的 Dockerfile 也被用于其他很多构建 Python 应用程序的镜像。
FROM crosbymichael/python
RUN pip install butterfly
RUN echo "root\nroot\n" | passwd root
EXPOSE 9191
ENTRYPOINT ["butterfly.server.py"]
CMD ["--port=9191", "--host=0.0.0.0"]
另一个:
FROM crosbymichael/python
RUN pip install --upgrade youtube_dl && mkdir /download
WORKDIR /download
ENTRYPOINT ["youtube-dl"]
CMD ["--help"]
正如你看到的,这使得使用你的基础镜像非常小,从而使你集中精力在应用程序上。
九 、持续系统集成了解下git
1.什么是持续集成?
持续集成(Continuous integration,简称CI)。
根据敏捷大师Martin Fowler的定义,“持续集成是一种软件开发实践。在持续集成中,团队成员频繁集成他们的工作成果,一般每人每天至少集成一次,也可以多次。每次集成会经过自动构建(包括自动测试)的检验,以尽快发现集成错误。许多团队发现这种方法可以显著减少集成引起的问题,并可以加快团队合作软件开发的速度。
为什么要持续集成?
1 快速发现错误:每完成一点更新,就集成到主干,可以快速发现错误,定位错误也比较容易。
2 防止分支大幅偏离主干:如果不是经常集成,主干又在不断更新,会导致以后集成的难度变大,甚至难以集成。
下面是持续集成的图谱介绍:
1 将更改提交到代码管理仓库
2 持续集成服务器收到请求拉取变更代码
3 持续集成服务器编译代码
4 持续集成服务器跑代码相关测试
5 持续集成服务器测试结束
6 持续集成服务器对结果进行反馈Docker在持续集成中的作用:Docker提供代码编译、打包、测试的相关环境。
优势:
1 环境可以是是任意版本
2 节省空间
3 环境相对隔离
2.什么是Git?
Git是一个开源的分布式版本控制系统,可以有效、高速的处理从很小到非常大的项目版本管理。Git 是 Linus Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控制软件。
Git常用命令:
1 初始化git项目
git init
2 查看当前项目状态
git status
3 新建文件并再次查看状态
echo “# My Project” > README.md
git status
4 记录当前操作,记录新加入的文件并再次查看状态
git add README.md
git status
5 记录当前更改并加以信息描述
git commit 文件名 -m ’add my first project’
6 查看提交历史
git log
7 新建远程仓库
git remote add origin https://github.com/limingios/git-test.git
8 同步到远程仓库
git push -u origin master
9 从远程代码库同步到本地
git pull origin master
10 与同步前对比变更
git diff HEAD
11 查看当前更改变更
git diff --staged
12 恢复到为更改状态
git reset README.md
13 覆盖本地文件
git checkout octocat.txt
14 新建分支
git branch feature1
15 切换分支
git checkout feature1
16 删除本地分支
git branch –d feature1
十、jenkins的使用
略