Docker之使用Dockerfile创建定制化镜像(四)–技术流ken

前言
在之前的博客《Docker端口映射及创建镜像演示(二)–技术流ken》,演示了如何使用一个现有容器创建一个镜像,以及镜像在阿里云的上传和下载。
但是这样的镜像有很大的局限性,不能根据我们的生产需要进行个性化定制,所以我们急需学习一种能够满足我们需要的制作镜像的工具。
这个时候Dockerfile就出现了。
使用dockerfile指令可以根据自己的需要,制作满足自己生产需要的镜像。
本篇博客将详细讲解如何使用dockerfile制作自己的专属镜像。
Dockerfile简介
镜像的定制实际上就是定制每一层所添加的配置、文件。如果我们可以把每一层修改、安装、构建、操作的命令都写入一个脚本,用这个脚本来构建、定制镜像,那么哪些无法重复的问题、镜像构建透明性的问题、体积的问题就都会解决。这个脚本就是 Dockerfile。
Dockerfile 是一个文本文件,其内包含了一条条的指令,每一条指令构建一层,
因此每一条指令的内容,就是描述该层应当如何构建
Dockerfile编写注意项
- # 备注
- 指令参数,指令的大小写不敏感
- 第一个非注释行必须是FROM指令
- 编写Dockerfile必须在一个目录下进行,这个目录称之为 工作目录(WORKSPACE)
- Dockerfile文件命令的首字母必须大写
- 制作镜像所要用的文件必须放在工作目录或者工作目录的子目录之下,不能放在父目录
- 可以通过隐藏文件 .dockeringnore 来指定不要放入到镜像中的文件,一行是一个文件,可以用通配符
- 基于dockerfile做镜像,本质上还是基于一个现有的镜像做新镜像
Dockerfile指令详解
1. FROM
作用:FROM 就是指定基础镜像,因此一个 Dockerfile 中 FROM 是必备的指令,并且必须是第一条指令
格式:
FROM <registry>:[tag]
FROM <registry>@<digest>
FROM 示例:
第一步:创建工作目录及dockerfile
[root@ken ~]# mkdir /ken [root@ken ~]# cd /ken [root@ken ken]# touch Dockerfile
第二步:写入from指令
docker.io:注册表
nginx:仓库
latest:版本号
[root@ken ken]# cat Dockerfile FROM docker.io/nginx:latest
2. LABEL
作用:设定一些元数据
格式:
LABEL 信息
LABEL示例:
LABEL author "ken"
3. COPY
作用:将工作目录下的文件复制到所做得镜像中的文件系统中
格式:
复制单个文件:COPY <src> <dest>
复制多个文件:COPY [<src> <src> <src>… <dest>]
COPY示例:
COPY passwd /data/
注意:
- 源文件路径用相对路径,目标一般用绝对路径
- 也可以通配符
- 源文件必须在工作目录或者工作目录的子目录中
- 目标路径可以不存在,会自动创建
- 如果源文件是一个目录,会自动递归复制目录下的文件到目标位置,但是目录自身不会复制
- 如果复制多个文件,或者源文件中用了通配符,那么目标路径必须以 / 为结尾
4. ADD
作用:和COPY类似,可以实现将文件和目录加载镜像中,但是区别是可以实现将tar包解压,也可以实现从网络下载文件到镜像
注意:下载的tar无法解压
格式
ADD <src> <dest>
ADD [“<src>” “<src>” “<src>” “<dest>”]
ADD示例:
ADD nginx-1.14.0.tar.gz /data/
5. WORKDIR
作用:相当于执行cd命令。切换目录,为后续的RUN、CMD、ENTRYPOINT 指令配置工作目录。
格式:
WORKDIR 容器目录
WORKDIR示例:
WORKDIR /pack/nginx/
6. VOLUME
作用:指定数据卷的挂载点
格式:
VOLUME 容器目录
VOLUME示例:
VOLUME /data/mysql/mysql3306/data
7. EXPOSE
作用:设置Docker容器内部暴露的端口号,如果需要外部访问,还需要启动容器时增加-p或者-P参数进行分配。
格式:
EXPOSE PORT/[PROTOCOL]
EXPOSE示例:
EXPOSE 80/tcp
9. ENV
作用:设置环境变量
格式:
ENV var value
ENV var1=value1 var2=value2 …
注意:
通过ENV所定义的变量是可以传递到容器之中,但是,在创建容器的时候,如果手动指定了变量的值,那么这个值会覆盖掉镜像中原有的值
ENV示例:
ENV pkgname=nginx-1.14.0.tar.gz root=/data/mysql/mysql3306/data
10. RUN
作用:基于镜像构建容器时候要执行命令
阶段:第一阶段,也就是构建镜像的时候执行
格式:
RUN 命令
RUN示例:
RUN tar xf $root$pkgname
11. CMD
作用:定义容器启动以后要默认运行的程序,pid为1的程序
阶段:第二阶段,也就是将镜像构成成容器的时候执行
注意:可以在启动容器的时候用指定的命令替换掉镜像所要执行的命令
CMD指定容器启动是执行的命令,每个Dockerfile只能有一条CMD命令,如果指定了多条,只有最后一条会被执行。如果你在启动容器的时候也指定的命令,那么会覆盖Dockerfile构建的镜像里面的CMD命令
格式:
CMD <命令> 相当于执行的是/bin/sh -c 命令,也相当于执行exec来运行命令
CMD [“<命令>”, “<参数>”, “<参数>”]
CMD [“<参数>”, “<参数>”] <<< 需要借助于ENTRYPOINT指令
CMD示例:
CMD mkdir /ken
12. ENTRYPOINT
作用:定义容器启动以后要默认运行的程序,pid为1的程序
注意:
在运行RUN的时候所执行的命令无法覆盖ENTRYPOINT中的命令
RUN 后面的命令会被以参数的方式追加到原本要执行的命令的末尾,而不是替换
基于一个镜像,在创建容器的时候,通过传递不同的参数实现创建不同的容器
每个 Dockerfile 中只能有一个 ENTRYPOINT,当指定多个时,只有最后一个起效
格式:
ENTRYPOINT [“执行命令”,”参数1″,”参数2″…]
ENTRYPOINT示例:
ENTRYPOINT [ "curl", "-s", "http://10.220.5.138" ]
例如如下CMD和ENTRYPOINT的结合
FROM nginx
label auther=ken
ARG name=ken
ENV path=/ken/
COPY test /data/
ADD https://mirrors.aliyun.com/centos/7/os/x86_64/Packages/audiocd-kio-devel-4.10.5-3.el7.i686.rpm $path
WORKDIR $path
RUN mkdir $name
VOLUME $path
EXPOSE 80
RUN mkdir /test1
CMD ["-g","daemon off;"]
ENTRYPOINT ["nginx"]
13. ARG
作用:定义变量,这个变量是用在第一阶段(构建镜像——build)
格式:
ARG 变量名=变量值
ARG示例:
ARG name=ken
补充:Dockerfile中ENV 和 ARG的区别
在指定docker build 过程中传参数,要用ARG
在执行docker run的过程中传参数,要用ENV
ARG构建参数和 ENV 的效果一样,都是设置环境变量。所不同的是, ARG 所设置的构建环境的
环境变量,在将来容器运行时是不会存在这些环境变量的
14. USER
作用:指定运行容器时的用户名和UID,后续的RUN指令也会使用这里指定的用户
该用户必须存在于容器的用户空间中(容器的文件系统的中的/etc/passwd中)
格式:
USER <UID>|<USERNAME>
USER示例:
user ken
15. HEALTHCHECK
作用:docker daemon检查docker容器是否正常,如果异常会将该容器stop
将容器stop的条件
1)主进程停止了
2)主进程工作在了后台
格式:
HEALTHCHECK [options] CMD
options
–interval=#s|m 指定健康检查的时间间隔(例如:30s,30m)
–timeout=#s|m 指定等待响应的超时时间
–start-period=#s|m 指定容器启动多久以后才可以做监控检查
–retries=# 指定重试次数
返回值
0:success
1:unhealth
HEALTHCHECK示例:
HEALTHCHECK --interval=5m --timeout=1s --retries=3 CMD curl http://10.220.5.138/ken.html || exit 1
16. SHELL
可以用来指定系统中默认的shell类型
格式:
SHELL [“/bin/sh”, “-c”] (linux系统中)
SHELL示例:
SHELL ["/bin/sh","-c"]
17. STOPSIGNAL
向容器中pid为1的进程发送一个信号,通过这个信号来关闭这个主进程
默认是15信号
格式:
STOPSIGNAL 数值
STOPSIGNAL示例:
STOPSIGNAL 9
18. ONBULID
作用:定义一个触发器,指定的命令在构建镜像时并不执行,用来实现当基于这个这个镜像做新镜像的时候要执行的命令
格式:
ONBUILD 其他指令
ONBUILD示例:
ONBUILD COPY ken /app/
Dokcerfile完整演示创建nginx镜像
根据上面各个指令的介绍,我就直接用上面写的dockerfile进行演示。整个dockerifle内容如下。
[root@ken ~]# vim /ken/Dockerfile FROM docker.io/nginx:latest LABEL author "ken" COPY ./passwd /data/ WORKDIR /pack/nginx/ ENV pkgname=nginx-1.14.0.tar.gz root=/data/mysql/mysql3306/data/ COPY nginx-1.14.0.tar.gz $root VOLUME $root EXPOSE 80/tcp RUN tar xf $root$pkgname CMD nginx -g "daemon off;"
第一步:构建镜像
build:是指根据dockerfile制作镜像
-t:指定一个tag标签
.:表示上下文。你也可以理解为dockfile所在的目录,但是并不是准确的
如果下方出现successfully就表示镜像已经构建成功了
[root@ken ken]# docker build -t ken:v1-0 . Sending build context to Docker daemon 1.021 MB Step 1/10 : FROM docker.io/nginx:latest ---> 568c4670fa80 Step 2/10 : LABEL author "ken" ---> Using cache ---> 80e4e5846fd9 Step 3/10 : COPY ./passwd /data/ ---> Using cache ---> 685a7ceb74b3 Step 4/10 : WORKDIR /pack/nginx/ ---> Using cache ---> 0fc65f8c36df Step 5/10 : ENV pkgname nginx-1.14.0.tar.gz root /data/mysql/mysql3306/data/ ---> Using cache ---> 3f6038473472 Step 6/10 : COPY nginx-1.14.0.tar.gz $root ---> Using cache ---> 0cbff6223d5b Step 7/10 : VOLUME $root ---> Using cache ---> b74ac1c36c31 Step 8/10 : EXPOSE 80/tcp ---> Using cache ---> 6863a87a61a2 Step 9/10 : RUN tar xf $root$pkgname ---> Using cache ---> b32ac636a389 Step 10/10 : CMD nginx -g "daemon off;" ---> Running in 02308825301d ---> 4a91d70a57eb Removing intermediate container 02308825301d Successfully built 4a91d70a57eb
第二步:查看镜像
可以发现构建的名为ken标签为v1-0的镜像已经存在了
[root@ken ken]# docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE ken v1-0 4a91d70a57eb 21 minutes ago 116 MB
第三步:启动容器
可以发现基于我们刚才的创建的镜像的容器已经顺利跑起来了。
[root@ken ken]# docker run -d --name ken3 -d ken:v1-0 11f492a28b943e619b0ed5d6b19f212f1c9cc47f9bdbe132845e7a7129e5b419 [root@ken ken]# docker container ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 11f492a28b94 ken:v1-0 "/bin/sh -c 'nginx..." 16 seconds ago Up 11 seconds 80/tcp ken3
第四步:登录容器
可以发现我们这个启动的容器里面已经有我们指定的工作目录
复制过来的passwd文件
已经下载并传送到/data下了
[root@ken ken]# docker exec -it ken3 bash root@11f492a28b94:/pack/nginx# ls /data/ mysql/ passwd root@11f492a28b94:/pack/nginx# ls /data/ mysql/ passwd oot@11f492a28b94:/pack/nginx# ls /data/mysql/mysql3306/data/nginx-1.14.0.tar.gz /data/mysql/mysql3306/data/nginx-1.14.0.tar.gz
这样基于dockerfile自主创建镜像的过程就演示完了,快去自己制作一个属于自己的镜像吧。
基于centos部署LAMP镜像
第一步:拉取centos7镜像
并按照如下的dockerfile初始化镜像
FROM centos:7
ENV container docker
RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i == \
systemd-tmpfiles-setup.service ] || rm -f $i; done); \
rm -f /lib/systemd/system/multi-user.target.wants/*;\
rm -f /etc/systemd/system/*.wants/*;\
rm -f /lib/systemd/system/local-fs.target.wants/*; \
rm -f /lib/systemd/system/sockets.target.wants/*udev*; \
rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \
rm -f /lib/systemd/system/basic.target.wants/*;\
rm -f /lib/systemd/system/anaconda.target.wants/*;
VOLUME [ "/sys/fs/cgroup" ]
CMD ["/usr/sbin/init"]
第二步:编写制作LAMP架构的dockerfile
FROM local/c7-systemd
COPY local.repo /etc/yum.repos.d/
COPY wordpress /var/www/html/
RUN yum -y install httpd mariadb-server php php-mysql; yum clean all; systemctl restart mariadb httpd;systemctl enable mariadb httpd.service
EXPOSE 80 3306
CMD ["/usr/sbin/init"]
1.使用第一步创建出来的镜像
2.把local.repo文件发送到镜像中,因为镜像文件没有mariad数据库
local.repo文件内容
[local]
name=local
enabled=1
gpgcheck=0
baseurl=https://mirrors.aliyun.com/centos/7/os/x86_64/
3.把配置好的wordpress安装包复制到网站根目录下
4.下载LAMP架构
5.暴露80 和3306 端口
6.启动
第三步:运行容器
[root@ken-node3 centos]# docker run -d -v /sys/fs/cgroup/:/sys/fs/cgroup/ -p 888:80 --privileged centos-wordpress:v1
–privileged 让容器能够获得更多特权,否则在容器内部不能使用systemctl,会报如下的错
Failed to get D-Bus connection: Operation not permitted
第四步:进入容器创建数据库
[root@ken-node3 centos]# docker exec -it f80ed6fb67b3 bash
[root@f80ed6fb67b3 /]# ls /var/www/html/
index.php wp-activate.php wp-config-sample.php wp-links-opml.php wp-register.php
license.txt wp-admin wp-config.php wp-load.php wp-settings.php
readme.html wp-app.php wp-content wp-login.php wp-signup.php
wordpress wp-blog-header.php wp-cron.php wp-mail.php wp-trackback.php
wordpress-3.3.1-zh_CN.zip wp-comments-post.php wp-includes wp-pass.php xmlrpc.php
[root@f80ed6fb67b3 /]# mysql
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 2
Server version: 5.5.60-MariaDB MariaDB Server
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MariaDB [(none)]> create database ken;
Query OK, 1 row affected (0.00 sec)
MariaDB [(none)]> grant all on *.* to ken@'localhost' identified by '123';
Query OK, 0 rows affected (0.00 sec)
MariaDB [(none)]> exit
Bye
第五步:浏览器访问
Docker 支持通过扩展现有镜像,创建新的镜像。
实际上,Docker Hub 中 99% 的镜像都是通过在 base 镜像中安装和配置需要的软件构建出来的。比如我们现在构建一个新的镜像,Dockerfile 如下:
① 新镜像不再是从 scratch 开始,而是直接在 Debian base 镜像上构建。
② 安装 emacs 编辑器。
③ 安装 apache2。
④ 容器启动时运行 bash。
构建过程如下图所示:
可以看到,新镜像是从 base 镜像一层一层叠加生成的。每安装一个软件,就在现有镜像的基础上增加一层。
问什么 Docker 镜像要采用这种分层结构呢?
最大的一个好处就是 – 共享资源。
比如:有多个镜像都从相同的 base 镜像构建而来,那么 Docker Host 只需在磁盘上保存一份 base 镜像;同时内存中也只需加载一份 base 镜像,就可以为所有容器服务了。而且镜像的每一层都可以被共享,我们将在后面更深入地讨论这个特性。
这时可能就有人会问了:如果多个容器共享一份基础镜像,当某个容器修改了基础镜像的内容,比如 /etc 下的文件,这时其他容器的 /etc 是否也会被修改?
答案是不会!
修改会被限制在单个容器内。
这就是我们接下来要学习的容器 Copy-on-Write 特性。
可写的容器层
当容器启动时,一个新的可写层被加载到镜像的顶部。
这一层通常被称作“容器层”,“容器层”之下的都叫“镜像层”。
所有对容器的改动 – 无论添加、删除、还是修改文件都只会发生在容器层中。
只有容器层是可写的,容器层下面的所有镜像层都是只读的。
下面我们深入讨论容器层的细节。
镜像层数量可能会很多,所有镜像层会联合在一起组成一个统一的文件系统。如果不同层中有一个相同路径的文件,比如 /a,上层的 /a 会覆盖下层的 /a,也就是说用户只能访问到上层中的文件 /a。在容器层中,用户看到的是一个叠加之后的文件系统。
- 添加文件
在容器中创建文件时,新文件被添加到容器层中。 - 读取文件
在容器中读取某个文件时,Docker 会从上往下依次在各镜像层中查找此文件。一旦找到,打开并读入内存。 - 修改文件
在容器中修改已存在的文件时,Docker 会从上往下依次在各镜像层中查找此文件。一旦找到,立即将其复制到容器层,然后修改之。 - 删除文件
在容器中删除文件时,Docker 也是从上往下依次在镜像层中查找此文件。找到后,会在容器层中记录下此删除操作。
只有当需要修改时才复制一份数据,这种特性被称作 Copy-on-Write。可见,容器层保存的是镜像变化的部分,不会对镜像本身进行任何修改。
这样就解释了我们前面提出的问题:容器层记录对镜像的修改,所有镜像层都是只读的,不会被容器修改,所以镜像可以被多个容器共享。
We stumbled over here different page and thought I may as well check things out. I like what I see so now i’m following you. Look forward to going over your web page again.|
thank you Cordia
Hey there! I realize this is kind of off-topic however I had to ask. Does building a well-established website such as yours require a lot of work? I am completely new to operating a blog however I do write in my diary daily. I’d like to start a blog so I can share my own experience and views online. Please let me know if you have any ideas or tips for brand new aspiring bloggers. Appreciate it!|
hi Jeremiah, it’s very esay to start your website. You just need to buy a server, I bought the Aliyun server in China, and then you need to deploy a LAMP architecture to upload your website.
The very next time I read a blog, Hopefully it won’t fail me just as much as this particular one. I mean, Yes, it was my choice to read, but I genuinely thought you would have something helpful to say. All I hear is a bunch of crying about something you could fix if you were not too busy searching for attention.
I just want to tell you that I am just all new to blogs and truly savored your blog site. More than likely I’m likely to bookmark your blog . You surely come with very good well written articles. Many thanks for revealing your blog site.
My relatives all the time say that I am wasting my time here at net, but I know I
am getting experience everyday by reading thes nice posts.
You have made some good points there. I looked on the web to learn more about the issue and found most individuals will
go along with your views on this site.
このご夫婦は揃って「BR03-92」を愛用していることでも知られています 私はデイト表示はあまり必要ない派なのですが、このモデルのデイト表示はあまり目立たず気になりません。
私はデイト表示はあまり必要ない派なのですが、このモデルのデイト表示はあまり目立たず気になりません。
航空機やミリタリー要素が強いせいか男性の利用者が目立っていますが、女性では沖縄出身の歌手、AKINAさんが「BRS-ホワイトセラミックファントム-R 」を愛用しています。
戦闘機のダッシュボードメーターをそのまま取り外してセットしたようなリアルな質感と、強烈な存在感を放つファッション性、そして同社製品が実際に仏空軍に制式採用されているというバックボーンも大きな魅力となっている。
ベル&ロスはドラマで使用されることも多く、岡田将生さんや大東駿介さんが撮影で身に着けています。
「ムーンウォッチ」の愛称で有名な「スピードマスター」の派生モデル「デイデイト」。
特にベル&ロスが悪いといってるのではありませんし、一生物だと言えるのであれば、購入候補にいれます。
の耐久性が難あり、マメに手入れしても数年で硬化、突然切れる。
ベル&ロスは2013年、ヴィンテージコレクションに新たに加わるニューラインである「スポーツ ヘリテージ」を発表しました。
中古、というとネガティブな印象もありますが、腕時計ではヴィンテージやアンティークと呼ばれ、希少性のためプレミア価格になることもしばしばあります。
お探しのモデルやご興味のある腕時計がございましたら【 価格・在庫など 】 是非一度お問い合わせ下さい! タカラ堂で取り扱っている時計はすべて、厳格なクオリティーチェックを受け、正規の販売ルートで入荷した正規品です。
ご贈答用として、置時計や掛時計等クロックへの文字入れやのし掛け、屋外時計の設置等お気軽にご相談くださいませ。
腕時計でもっともスタンダードな円形の文字盤です。
外出時に付けていたら、まず本体はコンクリ落ちで大ダメージ。
BR123、BR126共に1960年代のオリジナルデザインのラバーストラップかステンレスブレスレットを着用出来ます。
静岡本店3Fには、県内唯一のフランク・ミュラー専用サロンも構えています。
当店は「ベル&ロス」の正規代理店です。
正規品と同等品質のコピー品 https://www.watcher0769.com/one/page-3.html
爆安SALEが開催中
ブランドコピー靴通販ショップの爆安SALEが開催中
通販ショップは世界有名なブランドのシューズのスーパーコピー品を激安でお客様に提供しています。
高級の素材と高技術を結び付けて世界最高級のブランドコピー品だけ扱います。
ルイ・ヴィトン靴コピー、コピーシャネルシューズ、ミュウミュウサンダルコピー
今、いろいろブランド コピー新品が登場します。
ぜひおすすめです。
ルイヴィトンバッグ https://www.watcher007.com/watch/menu-pid-39.html
ブランドスマホケース/カバー激安通販ショップ
ご来店いただき誠にありがとうございます。
当店では「信頼第一、サービス第一」をモットーに、お客様第一主義で営業しております。取扱商品としては、iPhoneスマホケース、iPadケース、SAMSUNG GALAXY スマホケース、バッテリー&充電器や、関係する物などです。皆様のニーズにお応えすべく各種製品を取り揃えております。
ごゆっくりお買い物をお楽しみください。皆様のお求めになりたい商品がきっと見つかります。
休業日: 365天受付年中無休
バッグ,財布&小物専門店 https://www.watchergz.com/index.html
hello!,I like your writing so a lot! percentage we communicate
extra about your post on AOL? I need a specialist on this
area to resolve my problem. May be that is you! Looking forward to peer you.
nike magista obra fg vs nike mercurial superfly fg jordan retro 14 xiv hombres rojo and blanco zapatos nike mercurial superfly vi zoo lebron soldier 10 black and yellow nike air max 90 scenery verde world famous supreme air force 1
hscuae http://www.hscuae.com/
良いお店です。梱包に感動しました。今まで、他の店で購入した事がありますが、こんなに、丁寧な梱包は初めて見た。商品が、崩れない、梱包。ありがとうございます。
【最短当日発送】遅くとも1~2営業で出荷可能、全国一律送料無料。販売価格はフリーダイヤルにてご相談させてください♪クロエ トートバッグ エクリプス 8AS527 ブロンズ レザー新品 Chloe
dallas cowboys throwback uniforms for cheap nike air huarache junior gris naranja negro nike hypervenom 3 all red shoes celtics earned edition nike hypervenom neon todas rosado nike hyperdunk 2016 high uk zapatos
spike lee yankees billig air jordan 3 retro true blue for sale mn ray ban wayfarer small size los angeles angels hat grey jordan slippers negro and rojo azul rosado adidas gloro para uk
jordan retro 6 todas blanco nike kobe 10 elite low opening night apk barato cielo azul new balance trainers miami heat fitted hat for cheap black giannis antetokounmpo jersey for cheap harden
all black air jordan 15 22 chelsea 3th kit nike air max 90 boots review knitted baker boy cap unblocked air max tailwind 8 men cheap white and gold shoes men stephen curry all black shoes canada
negro naranja blanco air jordan cp3 nike hypervenom phelon size 3 nike lunarglide 6 black mens for cheap nike magista opus electro ptt nike lebron soldier 11 mujeres gris blanco zapatos mls earth day jerseys 2019 for cheap
I was able to find good information from your articles.
Feel free to visit my webpage Penney
These are actually impressive ideas in about blogging. You have touched some nice points here.
Any way keep up wrinting.
my web site: Jamey