Docker 最近很火,所以,也跟着未来的大趋势学下docker,并将docker 应用到项目开发中。
一、什么是docker
Docker 是一个开源的应用容器引擎,基于 Go 语言 并遵从Apache2.0协议开源。Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。
容器是完全使用沙箱机制
,相互之间不会有任何接口(类似 iPhone 的 app),更重要的是容器性能开销极低。
二、为何要使用容器?
那么应用容器长什么样子呢,一个做好的应用容器长得就好像一个装好了一组特定应用的虚拟机一样。比如我现在想用MySQL那我就找个装好MySQL的容器,运行起来,那么我就可以使用 MySQL了。
那么我直接装个 MySQL不就好了,何必还需要这个容器这么诡异的概念?话是这么说,可是你要真装MySQL的话可能要再装一堆依赖库,根据你的操作系统平台和版本进行设置,有时候还要从源代码编译报出一堆莫名其妙的错误,可不是这么好装。而且万一你机器挂了,所有的东西都要重新来,可能还要把配置在重新弄一遍。但是有了容器,你就相当于有了一个可以运行起来的虚拟机,只要你能运行容器,MySQL的配置就全省了。而且一旦你想换台机器,直接把这个容器端起来,再放到另一个机器就好了。硬件,操作系统,运行环境什么的都不需要考虑了
。
在公司中的一个很大的用途就是可以保证线下的开发环境、测试环境和线上的生产环境一致。当年在 Baidu 经常碰到这样的事情,开发把东西做好了给测试去测,一般会给一坨代码和一个介绍上线步骤的上线单。结果代码在测试机跑不起来,开发就跑来跑去看问题,一会儿啊这个配置文件忘了提交了,一会儿啊这个上线命令写错了。找到了一个 bug 提上去,开发一看,啊我怎么又忘了把这个命令写在上线单上了。类似的事情在上线的时候还会发生,变成啊你这个软件的版本和我机器上的不一样……在 Amazon 的时候,由于一个开发直接担任上述三个职位,而且有一套自动化部署的机制所以问题会少一点,但是上线的时候大家还是胆战心惊。
若果利用容器的话,那么开发直接在容器里开发,提测的时候把整个容器给测试,测好了把改动改在容器里再上线就好了。通过容器,整个开发、测试和生产环境可以保持高度的一致。
此外容器也和VM一样具有着一定的隔离性,各个容器之间的数据和内存空间相互隔离,可以保证一定的安全性。
三、安装docker
在 ubuntu 下使用 curl 命令进行安装
sudo apt install -y curl;
sudo curl -sSL https://get.docker.com/ | sh;
windows 安装请参考 docker 官网。
docker常用命令
容器生命周期管理 — docker [run|start|stop|restart|kill|rm|pause|unpause]
容器操作运维 — docker [ps|inspect|top|attach|events|logs|wait|export|port]
容器rootfs命令 — docker [commit|cp|diff]
镜像仓库 — docker [login|pull|push|search]
本地镜像管理 — docker [images|rmi|tag|build|history|save|import]
其他命令 — docker [info|version]
1、列出机器上的镜像(images):
docker images
其中我们可以根据REPOSITORY
来判断这个镜像是来自哪个服务器,如果没有 /
则表示官方镜像,类似于username/repos_name
表示Github的个人公共库,类似于regsistory.example.com:5000/repos_name
则表示的是私服。
IMAGE ID列其实是缩写,要显示完整则带上--no-trunc
选项。
2、在docker index中搜索image(search)
搜索的范围是官方镜像和所有个人公共镜像。NAME列的 / 后面是仓库的名字。
docker search sameersbn
3、从docker registry server 中下拉image或repository(pull)
Usage: docker pull [OPTIONS] NAME[:TAG]
上面的命令需要注意,在docker v1.2版本以前,会下载官方镜像的centos仓库里的所有镜像,而从v.13开始官方文档里的说明变了:will pull the centos:latest image, its intermediate layers and any aliases of the same id,也就是只会下载tag为latest的镜像(以及同一images id的其他tag)。
也可以明确指定具体的镜像:
4、从image启动一个container(run)
docker run
命令首先会从特定的image创之上create一层可写的container,然后通过start命令来启动它。停止的container可以重新启动并保留原来的修改。run命令启动参数有很多,以下是一些常规使用说明,更多部分请参考http://www.cnphp6.com/archive...
当利用 docker run 来创建容器时,Docker 在后台运行的标准操作包括:
- 检查本地是否存在指定的镜像,不存在就从公有仓库下载
- 利用镜像创建并启动一个容器
- 分配一个文件系统,并在只读的镜像层外面挂载一层可读写层
- 从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中去
- 从地址池配置一个 ip 地址给容器
- 执行用户指定的应用程序
- 执行完毕后容器被终止
Usage: docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
启动一个本地镜像:镜像名REPOSITORY+镜像TAG
> docker run -d sameersbn/postgresql:9.6-2
e527ef6698ea52bb78803facd5d2a6a8cbcdeb98ba052b3a0cdf78478d9acc53
5、停止运行容器
根据容器IDCONTAINER ID
来使运行的容器停止 docker stop CONTAINER ID
。
➜ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f72ed57c80f8 sameersbn/redis:latest "/sbin/entrypoint.sh" 8 minutes ago Up 8 minutes 6379/tcp wonderful_bassi
e527ef6698ea sameersbn/postgresql:9.6-2 "/sbin/entrypoint.sh" 14 minutes ago Up 13 minutes 5432/tcp pensive_keller
➜ docker stop f72ed57c80f8
或者使用容器的别名来启动:
docker start MyWordPress
更多命令请看:docker常用命令详解
四、几个重要的概念
在使用docker时,我们得先弄清楚docker的几个重要的名词。
Docker生态
Docker生态就像 iPhone 的生态一样,Docker仓库
相当于 IPhone 的 App Store
,docker自身程序
相当于IOS系统
。
镜像与容器
镜像(image):指的是以分层的、可以被 LXC/libcontainer
理解的文件存储格式。Docker的应用都是以这种格式发布到Docker仓库中,供大家使用。
容器(container):把应用镜像从 Docker 仓库下载到本地机器上,以镜像为模板,在一个容器类虚拟机中把这个应用启动,这个虚拟机叫做容器。
可以先简单的理解,仓库中的应用都以镜像存在,从仓库中拉取镜像到本地的,叫容器
。
五、安装镜像docker-gitlab
gitlab环境配置要求比较高,可用内存必须2G以上,2核CPU,否则跑不起来。
1.安装
gitlab 镜像地址:docker-gitlab
Step 1. Launch a postgresql container
docker run --name gitlab-postgresql -d \
--env 'DB_NAME=gitlabhq_production' \
--env 'DB_USER=gitlab' --env 'DB_PASS=password' \
--env 'DB_EXTENSION=pg_trgm' \
--volume $HOME/docker/gitlab/postgresql:/var/lib/postgresql \
sameersbn/postgresql:9.6-2
Step 2. Launch a redis container
docker run --name gitlab-redis -d \
--volume $HOME/docker/gitlab/redis:/var/lib/redis \
sameersbn/redis:latest
Step 3. Launch the gitlab container
docker run --name gitlab -d \
--link gitlab-postgresql:postgresql --link gitlab-redis:redisio \
--publish 10022:22 --publish 10080:80 \
--env 'GITLAB_PORT=10080' --env 'GITLAB_SSH_PORT=10022' \
--env 'GITLAB_SECRETS_DB_KEY_BASE=long-and-random-alpha-numeric-string' \
--env 'GITLAB_SECRETS_SECRET_KEY_BASE=long-and-random-alpha-numeric-string' \
--env 'GITLAB_SECRETS_OTP_KEY_BASE=long-and-random-alpha-numeric-string' \
--volume $HOME/docker/gitlab/gitlab:/home/git/data \
sameersbn/gitlab:10.2.2
--volume 方法解释:
--volume $HOME/docker/gitlab/postgresql:/var/lib/postgresql
➜ ~ echo $HOME
/Users/kaiyiwang
注意: --volume $HOME/docker
是宿主机的环境,/var/lib/
为容器环境.
OK,安装好之后,我们可以通过命令来查看 docker 进程
docker ps
再次启动
容器命令:
前边我们已经安装镜像到本地,如果关闭docker服务之后,容器就会停止运行,再次启动docker之后,我们不需要再次使用 docker run -d images
,而只需启动容器即可。
docker ps
:查看运行的容器。docker ps -a
:查看所有已经安装的容器
开启容器:
docker start gitlab-postgresql
2.测试gitlab
使用 ifconfig 命令查看本机IP,因为gitlab默认的服务为 10080
,所以,我们可以根据我们的IP和端口访问到gitlab服务:http://192.168.1.101:10080/
gitlab页面:
在 gitlab 上新建一个 test 测试库:
使用 docker 搭建 gitlab服务是不是超级方便,不用做什么配置^_^。
相关文章:GitLab的简单使用
六、项目管理系统Redmine
Redmine 是一套跨平台的管理系统,它通过“项目(project)”的形式把成员、任务(问题)、文档、讨论及各种形式的资源整合在一起,大家参与更新任务、文档等内容来推动项目的进度,另外,它还集成了wiki文档、版本控制、bug跟踪等功能。
1.搭建Redmine服务
在这里,我们使用 sameersbn/docker-redmine 镜像,项目地址为:https://github.com/sameersbn/...。
拉取镜像:
docker pull sameersbn/redmine:latest
快读启动:
Step 1. Launch a postgresql container
docker run --name=postgresql-redmine -d \
--env='DB_NAME=redmine_production' \
--env='DB_USER=redmine' --env='DB_PASS=password' \
--volume=$HOME/docker/redmine/postgresql:/var/lib/postgresql \
sameersbn/postgresql:9.6-2
Step 2. Launch the redmine container
docker run --name=redmine -d \
--link=postgresql-redmine:postgresql --publish=10083:80 \
--env='REDMINE_PORT=10083' \
--volume=$HOME/docker/redmine/redmine:/home/redmine/data \
sameersbn/redmine:latest
2.测试
Redmine
Docker指令中,我们把Redmine的对外服务端口映射到10083,所以,我们可以通过
访问该地址:http://192.168.1.101:10083/,查看该服务是否安装成功。
安装成功,^_^
七、docker容器名称冲突
我们使用ps -a
这个命令,我们可以观察到gitlab-postgresql的状态为已经存在了。
我们用rm
命令删除这个容器,如下面命令所示:
sudo docker rm gitlab-postgresql
重新建立gitlab-postgresql
这个容器:
docker run --name gitlab-postgresql -d \
--env 'DB_NAME=gitlabhq_production' \
--env 'DB_USER=gitlab' --env 'DB_PASS=password' \
--env 'DB_EXTENSION=pg_trgm' \
--volume $HOME/docker/gitlab/postgresql:/var/lib/postgresql \
sameersbn/postgresql:9.6-2
八、挂载目录
使用镜像 nginx:latest
,以后台模式启动一个容器,将容器的 80
端口映射到主机的 80
端口,主机的目录 /data
映射到容器的 /data
。
docker run -p 80:80 -v /data:/data -d nginx:latest
将Mac的本地目录挂栽倒容器tensorflow/tensorflow
的/notebooks
目录
docker run -it -v /Users/kaiyiwang/Code/ai/notebooks:/notebooks -d tensorflow/tensorflow
如果直接挂载会报出这样的错误:
44a574c965c83688221798c5d70fff2a7badd3aad04dd071246d8f487bda5225
docker: Error response from daemon: Mounts denied:
The path /AI/tensorflow
is not shared from OS X and is not known to Docker.
You can configure shared paths from Docker -> Preferences... -> File Sharing.
See https://docs.docker.com/docker-for-mac/osxfs/#namespaces for more info.
在mac上面使用Docker挂载目录时,需要先在Docker->preference
中添加该目录,才能进行挂载!
再重试一次挂载:
➜ tensorflow docker run -it -v /Users/kaiyiwang/Code/ai/notebooks:/notebooks -d tensorflow/tensorflow
d1fceb76e44c4050c878a6ce996f59d8252c59d082293674db2ac043e8607f14
➜ tensorflow
可以看到挂载成功
九、进入容器内部
// 进入容器内部
sudo docker exec -it c7efe /bin/bash
c7efe
为容器ID前几位,通过上边的命令即可进入容器内部。
进入jupyter
➜ tensorflow docker exec -it c7efe /bin/bash
root@c7efe77f377a:/notebooks#
root@c7efe77f377a:/notebooks# jupyter notebook list
Currently running servers:
http://localhost:8888/?token=44077e3f129fdbf0b26676b5414a36ce8b6a56627ad84a6e :: /notebooks
root@c7efe77f377a:/notebooks#
十、Docker重启
在宿主机环境下重启容器或整个docker
[corwien@lnp php_log]$ sudo docker ps # 查看docker进程
[corwien@lnp php_log]$ sudo docker restart bfc6 # docker 容器重启
# service docker restart
sudo systemctl restart docker 如果网络断了,则重启docker就可以了
查看DNS(docker容器在创建实例的时候会拷贝宿主机的到容器里边,如果宿主机的DNS改变了,则需要重新加载容器的)
[root@bfc6f9d528a5 /]# cat /etc/resolv.conf
十一、将对容器的修改提交到镜像
在容器内部进行了一些修改之后,我们想把这些保存下来,不想这些在退出或停止这个容器后丢失这些修改,并且我们还想把这些修改作为其他容器的基础进行重用。
通过 docker commit 命令提交对容器的修改,并创建一个新镜像。
比如我们新建了一个学习swoole的Ubuntu环境的容器,现在要对这个容器提交生成新的镜像,即:
查看容器:
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5ee6bfcc1310 7698f "/bin/bash" 4 days ago Up About an hour 0.0.0.0:2221->22/tcp, 0.0.0.0:8880->80/tcp confident_jones
新生成镜像:
$ docker commit 5ee6 ubuntu:swoole
可以看到,新生成了一个swoole标签的镜像:
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu swoole 2fb6cd672bdc 39 seconds ago 530MB
ubuntu latest a2a15febcdf3 2 weeks ago 64.2MB
daocloud.io/ubuntu latest 7698f282e524 3 months ago 69.9MB
jaspeen/oracle-11g latest 0c8711fe4f0f 3 years ago 281MB
docker diff
通过 docker diff 命令来查看在容器中对镜像做出的修改:
$ docker diff 5ee6
...
A /lib/cpp
C /root
C /root/.profile
A /root/.rediscli_history
A /root/.ssh
A /root/.ssh/id_rsa
A /root/.ssh/id_rsa.pub
A /root/.ssh/known_hosts
A /root/.viminfo
A /root/.wget-hsts
A /root/.bash_history
A /root/.gitconfig
A /work
C /tmp
A /tmp/pear
A /tmp/pear/temp
C /var
C /var/lib
C /var/lib/systemd
A 表示文件或者文件夹是新增的,C表示文件内容有修改,D表示该项目已经被删除。
将镜像和容器保存为tar文件进行共享
对于已有镜像,可以使用docker命令行的 save
和 load
命令来创建一个压缩包;而对于容器,可以使用 import
和 export
进行导入导出操作。
镜像操作:
docker save -o update1.tar b2367
docker load < update1.tar
容器:
docker export e556 > update.tar
docker import - update < update.tar
将修改的镜像发布到 docker hub
https://hub.docker.com 和GitHub一样需要注册一个账号。
~ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu swoole 2fb6cd672bdc 24 minutes ago 530MB
使用docker tag 命令使用你在 Docker Hub上的仓库为这个镜像打上标签,如下所示:
➜ ~ docker tag 2fb6c digtime/ubuntu-swoole
➜ ~ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
digtime/ubuntu-swoole latest 2fb6cd672bdc 27 minutes ago 530MB
ubuntu swoole 2fb6cd672bdc 27 minutes ago 530MB
推送到docker hub:
$ docker push digtime/ubuntu-swoole
The push refers to repository [docker.io/digtime/ubuntu-swoole]
f43e13b8cb69: Retrying in 1 second