docker基本操作(ubuntu)

本人使用docker,主要是为了将服务部署在容器里,需要的时候直接运行容器,这样就不用每次部署,都要在一个新的系统上从头开始装一遍各种库,配置各种环境变量之类的工作了。

docker简介

强烈推荐这篇文章10分钟看懂Docker和K8S,docker讲的非常清楚,也很生动(后面k8s的部分就不用看了)。

了解docker的基本概念之后,再把后面我写的这些做一遍,我觉得就基本够用了。

安装docker

环境:ubuntu1604/1804

命令如下:

apt-get update
apt-get install docker.io

安装之后,docker会在后台运行,之后也会开机自启动。

获取原始镜像

我们需要的原始镜像,例如ubuntu镜像centos镜像,最开始都需要从docker hub获取。

docker hub就类似于github,是一个官方的免费的,用来存镜像的仓库,还可以做镜像的版本管理,等下看了后面的命令就会发现,docker的命令也跟git很像。

配置镜像加速

从docker hub拉取镜像之前,最好配置一下镜像加速,因为docker hub是国外的网站,直接用的话网速很慢,配置命令如下:

sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://9qk572kh.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker

注意:其中的加速器url是阿里云分配给我的账号的,强烈建议,去阿里云注册一个账号,然后开通容器镜像服务,这个服务是免费的,除了可以提供加速器url,还提供免费的镜像仓库,跟docker hub相比,这个仓库在国内,网速要快很多,尤其是如果你用阿里云服务器的话,从阿里云镜像仓库拉镜像是非常快的。

从docker hub拉取镜像

配置好镜像加速之后,就可以从docker hub拉取镜像了。

因为我的部分服务需要部署在ubuntu1804,所以我直接从docker hub拉了一个ubuntu1804镜像下来。

打开docker hub网站也是非常慢的,耐心等待一会儿,打开以后搜索ubuntu1804,我们可以看到ubuntu官方的镜像,和一些其他的star比较高的,我没有选择ubuntu官方的,因为是在是太纯净了,连apt源都是空的。。。我选择的是waffleimage/ubuntu18.04这个镜像,后面用着感觉还可以,拉取命令如下:

docker pull waffleimage/ubuntu18.04:latest

拉取之后,使用docker images命令查看,就可以看到你本地的镜像了。

我们可以看到,一个镜像,除了名字,还有一个TAG,这个tag,就相当于版本号,当我们修改了这个镜像之后,可以给它打上一个新的tag。 

运行容器

我们拉下来的容器镜像,就相当于我们给电脑装系统的时候用的镜像。有了ubuntu1804镜像,接下来要做的就是用它构建一个正常运行的ubuntu1804系统了。

docker run命令,实现的就是基于镜像构建一个容器。docker run命令可以添加很多选项,我们从最简单的说起。

构建基本容器

首先,什么都不考虑,就是构建一个容器,使用如下命令:

docker run --name test -it waffleimage/ubuntu18.04:latest /bin/bash

这条命令执行完,你会发现,我们进入到了容器内部,这时我们所做的一切操作,都仅对容器生效,对宿主机不会产生影响,就好比是我们在一个虚拟机内部操作一样。 

接下来解释一下几个选项:

--name 容器名字

 这个选项用于给容器起名字,docker run命令执行完之后,docker会为容器生成一个随机字符串作为容器id,如果不带上这个--name选项,也会随机生成一个容器名字,但是,我强烈建议加上这个选项,自己给容器命名,这样当系统同时运行多个容器时,你可以通过你自己起的名字,确定每个容器分别是做什么的

-it

这个选项其实是-i和-t两个选项,结合在一起使用的效果就是,容器运行起来之后,建立一个终端,然后执行指定的命令,这个指定的命令是什么呢,就是镜像后面的/bin/bash。

这时我们输入exit可以退出容器,回到宿主机。

这时使用以下命令,可以查看我们本机上的所有容器。

docker ps -a

 我们可以看到我们刚刚构建的名为test的容器。

这里,需要注意的是STATUS这一栏,我们看到我们刚刚创建的容器的状态是Exited (0) 2 minutes ago,也就是已经退出了,为什么容器没有自己在后台运行呢?这也是需要注意的一点,容器内部如果没有前台运行的进程,就会认为自己无事可做,就会退出了。 

构建容器,并将宿主机文件拷贝进去

目前,我们有一个原始ubuntu1804镜像,我们希望将一些服务的程序部署进去,这些程序在宿主机上,这时,我们可以使用-v选项,在构建容器的同时,将宿主机上的文件拷贝进去,命令如下:

docker run --name test -v /data:/data -it waffleimage/ubuntu18.04:latest /bin/bash

这样,我们就可以将宿主机/data路径下的东西拷贝到容器的/data路径下了。 

构建容器并在后台运行

我们用来构建docker的镜像,通常里面已经部署好了服务,并且有一个初始化脚本,我们构建容器之后并不需要进去操作什么,只需要容器构建之后执行我们写好的脚本,然后安静的在后台运行就好了,欧克,那就用下面这条命令:

docker run --name test -dit waffleimage/ubuntu18.04:latest /bin/bash /home/start.sh 123.45.67.89

跟上一条命令,相比,这条命令增加了-d,/bin/bash后面增加了一个脚本,脚本后面还有一个ip地址,我逐个解释一下。

-d

就是让容器在后台运行,这样docker run运行完我们不会再进入容器内部。

/bin/bash/后面的脚本,就是上面所说的,我们希望容器构建之后,运行的初始化脚本,注意要加上绝对路径,另外这么写,意味着你这个镜像里,/home/路径下确实有一个叫start.sh的脚本。

脚本后面的ip,是脚本的参数(只是个例子,具体填什么参数看你的脚本需要什么参数),参数可以有多个,依次往后写就可以了。

注意,你的脚本里一般都是在后台运行一些服务,之前我们特别提到了,容器内部如果没有前台运行的进程,就会自己退出,我们当然不希望容器退出,而是默默的在后台,运行着我们设置好的服务。为此我们需要保证容器内部有一个正在运行的前台进程。

一种做法是,在脚本的最后一行加入一个可以前台运行的命令,比如top命令。

构建容器并使用主机网络

如果我们在容器里运行的是服务器进程,那么我们肯定希望外面的客户端可以访问容器里的服务,于是乎就涉及到了容器的网络问题。

如果你用过虚拟机的话,会知道虚拟机有主机模式(host)和桥接模式(bridge),其中,主机模式就是和宿主机共享网络,也就是容器和宿主机ip一致,端口公用,宿主机的网络能干的事情,容器也都可以。

使用host网络模式,需要在命令里加一个--net=host选项,如下所示:

docker run --net=host --name test -dit waffleimage/ubuntu18.04:latest /bin/bash /home/start.sh 123.45.67.89

构建容器并使用桥接网络

桥接网络,我的理解就是宿主机上运行了一个路由器,这个路由器将宿主机的网络和容器内部的网络打通,所有发往宿主机的包,如果满足一定规则,就会被这个路由器转发到容器的网络里。

如果要使用桥接网络模式,首先需要创建一个子网,这个子网就是容器内部会使用的网络。

创建子网命令如下:

docker network create --subnet=192.168.1.0/24 test_network

这条命令创建了一个网络为192.168.1.0的网络,子网掩码为255.255.255.0,网络名称为test_network。

创建之后,我们可以使用如下命令查看我们创建的子网:

docker network ls

 结果如下:

 

接下来我们使用如下命令,将容器内部的网络设置为刚刚建立的test_network:

docker run --ip=192.168.1.200 --net test_network --name test -dit -p 3306:3306 -p 7071:7071/udp waffleimage/ubuntu18.04:latest /bin/bash /home/start.sh 123.45.67.89

 解读一下:

--ip=192.168.1.200 --net test_network

这两个选项,将容器内部的网络设置为了我们刚刚创建的test_network,同时将容器内部的ip设置为了192.168.1.200。

 -p 3306:3306 -p 7071:7072/udp

-p选项是端口映射,默认是tcp,如果是udp端口需要标注在后面,上面说过,宿主机网络会将满足指定规则的包,发送到容器内部,这个指定规则,就是通过端口映射实现的, 上面配置的效果就是,将发往宿主机3306端口的tcp包,发送到容器内部的3306端口,将发往宿主机7071端口的udp包,发送到容器内部的7072端口。

容器运行时的网络模式选择

既然有多种网络模式,那么一个重要的问题就是,如何选择?

我们项目最开始使用的是桥接模式,这样的好处是,不管容器部署在哪个宿主机上,容器内部的网络都是不变的,即内部的ip永远不需要再重新配置了。

如果使用host模式,优点是不用配置端口映射,这样用起来比较方便,但容器内部的ip也会随着宿主机的ip改变,这样的话有时候就需要在构建容器之后修改一下配置。

之前有一本书上写redis集群的搭建必须使用host模式,是不是必须我没有考证过,但是为什么这样说,我是可以理解的,我搭建过consul集群、zookeeper集群、mysql集群,这些集群的配置文件,都会有类似下面这样的一段:

myid=1
server1=192.168.1.31
server2=192.168.1.32
server3=192.168.1.33

也就是指定集群里所有机器的ip,以及自己是哪一个。

如果用桥接模式的话,ip地址如果填宿主机的ip,容器内部绑定不上,如果填容器内部的ip,其他节点连不上,所以,必须容器内部ip和宿主机ip一致才可以避免这个问题。

当然了,像consul可以在启动的时候同时制定内网ip和外网ip,就可以解决这个问题,如果没有这个启动选项的话,可能就真的只能用host模式了。

构建一个可以gdb调试的容器

初次使用docker部署了C程序之后,想用gdb调试发现竟然不行,查了一下,需要在构建容器时增加--cap-add=SYS_PTRACE选项,亲测可用~

操作容器

进入容器操作

如果我们的容器正在后台运行,我们想进入容器内部操作一番,该怎么办呢?

可以使用docker exec命令,具体如下:

docker exec -it 容器id /bin/bash

这样你就进入容器内部了,操作完成后,输入exit即可退出,回到宿主机~ 

容器的启动/停止/重启

命令依次如下:

docker start 容器id
docker stop 容器id
docker restart 容器id

上传镜像

在最开始,我们拉取了一个原始ubuntu1804镜像下来,之后,我们将需要的服务部署进去了,这时我们想要保存一个版本,也就是把现有的部署好的容器重新打包成镜像,然后把它上传到镜像仓库,这样以后再想在其他机器部署,直接从仓库拉取部署好服务的镜像然后运行即可。

将容器打包成镜像

注意:打包这个词是口头语,并非专业名词,只是为了形容这个过程。。。

注意:运行过程中的容器最好先关闭,再打包

我之前看网上一些操作,直接把运行中的容器打包成镜像,于是我直接将运行过程中的mysql集群管理节点打包,结果打包完其他节点和管理节点的连接都断了,也就是说打包过程对容器的状态是有影响的。

打包命令是docker commit,具体命令如下:

docker commit -a "作者信息" -m "提交信息" 容器id 镜像:tag

比如我们在ubuntu里部署了mysql,想把它存成一个叫ubuntu1804_mysql的镜像,就可以这样:

docker commit -a "djqueen" -m "install mysql" 容器id ubuntu1804_mysql:v1.0

当然,也可以不改镜像名称,只改tag。

将镜像推送至仓库

注意,我们是从一个公开的仓库拉取的ubuntu1804镜像,但是人家的仓库是不会让我们随便推一个我们的版本上去的,如果我们想保存自己的版本,有几个办法:

docker hub

想把镜像推送到docker hub,需要在docker hub创建账号,然后在自己的账号里新建仓库,然后把我们的镜像推进去。

注意:这时我们的镜像名就不是随便起了,必须是“账号/仓库名”,这样才能推到我们自己的仓库里,比如你的docker hub账号叫djq,仓库叫mysql,那么你的镜像就要叫djq/mysql。

另外,由于是我们的私有仓库,我们不希望别人拉我们的镜像,或者把镜像推送到我们的仓库,所以不管是执行docker pull还是docker push之前,都需要先登录:

docker login

然后会让你输入用户名和命名,就是你docker hub的用户名和密码。

登录上之后,就可以推送了,使用docker push命令:

docker push image:tag

再次提示,image是账户名/仓库名,这样docker才知道push到哪个人的哪个仓库里面去。

阿里云仓库

这里再次提到了阿里云,嗯,因为确实很方便,而且免费。。。

在此,我再次强烈推荐使用阿里云的容器镜像服务做你的容器镜像仓库,而不是docker hub,因为阿里云服务器在国内,确实是比docker hub快一些的,操作也很简单,首先建立一个仓库:

点击创建镜像仓库,然后输入命名空间和仓库名称,这两个就类似docker hub的用户名和仓库名称,然后点击下一步:

这里选择,本地仓库,然后点击创建,你就有了一个跟docker hub上的仓库一样的镜像仓库。

你可能好奇和github这样的代码仓库有什么关系,我也没有用过,我猜可能是和Dockerfile有关,关于Dockerfile,这里简单说明一下。

Dockerfile就是一个类似脚本的文本文件,里面有一些命令,和shell命令语法基本一样,但是也有一些dockerfile的特别语法,这些命令基本就是,首先拉取一个镜像,然后在镜像里配置环境变量,然后部署程序,然后运行脚本,诸如此类,就是用于在某个镜像的基础上构建另一个镜像。也就是说我们的镜像,可以直接存在仓库,也可以只把构建命令存起来,这样,需要的时候,在你的机器上运行一下这个Dockerfile,你想要的镜像就会在本地被创建了。

回到阿里云的使用,创建完仓库之后,点进去,你会发现,简直太贴心了,登录,推拉怎么实现,都有说明!

总之我在使用过程中,没有遇到任何问题,只有两个字,舒服!

 搭建本地仓库

当然,如果你不放心放在公网的仓库上,或者你的镜像只是公司内部用,那你完全可以在公司的某台机器上自己搭一个私有仓库,这样的话,公司内部的机器拉取镜像,走的就是内网,速度那肯定是没得说。

搭建本地仓库也并不复杂,假设我们将仓库搭建在ip为192.168.90.51的内网机器上。

首先,从docker hub上拉取registry镜像,这是官方提供的,用来做仓库的镜像:

docker pull registry

然后,启动registry容器,启动时加上-d,即以守护进程启动,这样服务器每次重启registry容器都会运行,而registry容器就是一个私有仓库,仓库名称为192.168.90.51:5000。

docker run -d -p 5000:5000 --restart=always -v /opt/registry:/var/lib/registry registry

容器一跑起来,仓库其实就搭建好了,但是要注意:dockers registry V2 版本客户端默认使用https协议去push镜像到仓库服务 器,而现在我们的仓库服务器只配置了支持http,所以客户端会push镜像失败。如要希望docker客户端支持http协议,需在启动docker时加入参数--insecure-registry your_registry_ip:port,我们可以编辑docker服务的启动文件docker.service把这个参数配置进去:

vim /lib/system/system/docker.service

注意:不同版本的linux里,docker.service的路径可能不一样,你可以先找一下这个文件的位置。

修改内容如下:

ExecStart=/usr/bin/dockerd  --insecure-registry 192.168.90.51:5000

修改后重新加载daemon:

systemctl daemon-reload

然后重启docker:

systemctl restart docker.service

这时就可以用我们的仓库了,首先给之前的某个镜像打上新的标签:

docker tag bitbjtu/pdds:v1.1 192.168.90.51:5000/hub_name:tag

注意:任何机器要从私有仓库pull镜像或者向私有仓库push镜像都需要先修改docker.service文件,而不是只有运行registry的那台机器上改

关于k8s

当我们的服务都以容器的形式部署时,一个新的问题诞生了,这么多容器,怎么管理,难道自己一个一个的区docker run吗?

肯定是有自动化管理工具的,那就是k8s,k8s是一种容器编排工具,有了k8s,你就可以轻松的在系统里增加,删除容器了。

不过,k8s我还没有自己部署过,只能告诉大家用这个东西,如果以后我搞明白了,会补充在这里的,哈哈~

发布了39 篇原创文章 · 获赞 25 · 访问量 12万+

猜你喜欢

转载自blog.csdn.net/u013536232/article/details/104297670