標籤: 台北網頁設計

  • Docker Dockerfile 指令詳解與實戰案例

    Docker Dockerfile 指令詳解與實戰案例

     

    Dockerfile介紹及常用指令,包括FROM,RUN,還提及了 COPY,ADD,EXPOSE,WORKDIR等,其實 Dockerfile 功能很強大,它提供了十多個指令。

     

    Dockerfile介紹

    Dockerfile 是一個用來構建鏡像的文本文件,文本內容包含了一條條構建鏡像所需的指令和說明。

    在Docker中創建鏡像最常用的方式,就是使用Dockerfile。Dockerfile是一個Docker鏡像的描述文件,我們可以理解成火箭發射的A、B、C、D…的步驟。Dockerfile其內部包含了一條條的指令,每一條指令構建一層,因此每一條指令的內容,就是描述該層應當如何構建。

    FROM 指令-指定基礎鏡像

    所謂定製鏡像,那一定是以一個鏡像為基礎,在其上進行定製。而 FROM 就是指定基礎鏡像,因此一個 Dockerfile 中 FROM 是必備的指令,並且必須是第一條指令。如下:

    FROM centos

     

    MAINTAINER 維護者信息

    該鏡像是由誰維護的

    MAINTAINER lightzhang lightzhang@xxx.com

     

    ENV 設置環境變量

    格式有兩種:

    ENV <key> <value>
    ENV <key1>=<value1> <key2>=<value2>...

     

    這個指令很簡單,就是設置環境變量而已,無論是後面的其它指令,如 RUN,還是運行時的應用,都可以直接使用這裏定義的環境變量。

    ENV VERSION=1.0 DEBUG=on \
        NAME="Happy Feet"
    

    這個例子中演示了如何換行,以及對含有空格的值用雙引號括起來的辦法,這和 Shell 下的行為是一致的。

    下列指令可以支持環境變量展開:

    ADD、COPY、ENV、EXPOSE、FROM、LABEL、USER、WORKDIR、VOLUME、STOPSIGNAL、ONBUILD、RUN。

    可以從這個指令列表裡感覺到,環境變量可以使用的地方很多,很強大。通過環境變量,我們可以讓一份 Dockerfile 製作更多的鏡像,只需使用不同的環境變量即可。

     

    ARG 構建參數

    格式:ARG <參數名>[=<默認值>]

    構建參數和 ENV 的效果一樣,都是設置環境變量。所不同的是,ARG 所設置的構建環境的環境變量,在將來容器運行時是不會存在這些環境變量的。但是不要因此就使用 ARG 保存密碼之類的信息,因為 docker history 還是可以看到所有值的。

    Dockerfile 中的 ARG 指令是定義參數名稱,以及定義其默認值。該默認值可以在構建命令 docker build 中用 –build-arg <參數名>=<值> 來覆蓋

    在 1.13 之前的版本,要求 –build-arg 中的參數名,必須在 Dockerfile 中用 ARG 定義過了,換句話說,就是 –build-arg 指定的參數,必須在 Dockerfile 中使用了。如果對應參數沒有被使用,則會報錯退出構建。

    從 1.13 開始,這種嚴格的限制被放開,不再報錯退出,而是显示警告信息,並繼續構建。這對於使用 CI 系統,用同樣的構建流程構建不同的 Dockerfile 的時候比較有幫助,避免構建命令必須根據每個 Dockerfile 的內容修改。

     

    RUN 執行命令

    RUN 指令是用來執行命令行命令的。由於命令行的強大能力,RUN 指令在定製鏡像時是最常用的指令之一。其格式有兩種:

    shell 格式:RUN <命令>,就像直接在命令行中輸入的命令一樣。如下:

    RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html

     

    exec 格式:RUN [“可執行文件”, “參數1”, “參數2”],這更像是函數調用中的格式。

    Dockerfile 中每一個指令都會建立一層,RUN 也不例外。每一個 RUN 的行為,都會新建立一層,在其上執行這些命令,執行結束后,commit 這一層的修改,構成新的鏡像。

    Dockerfile 不推薦寫法:

     1 FROM debian:stretch
     2 
     3 RUN apt-get update
     4 RUN apt-get install -y gcc libc6-dev make wget
     5 RUN wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz"
     6 RUN mkdir -p /usr/src/redis
     7 RUN tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1
     8 RUN make -C /usr/src/redis
     9 RUN make -C /usr/src/redis install
    10 RUN rm redis.tar.gz

    上面的這種寫法,創建了 8 層鏡像。這是完全沒有意義的,而且很多運行時不需要的東西,都被裝進了鏡像里,比如編譯環境、更新的軟件包等等。最後一行即使刪除了軟件包,那也只是當前層的刪除;雖然我們看不見這個包了,但軟件包卻早已存在於鏡像中並一直跟隨着鏡像,沒有真正的刪除。

    結果就是產生非常臃腫、非常多層的鏡像,不僅僅增加了構建部署的時間,也很容易出錯。 這是很多初學 Docker 的人常犯的一個錯誤。

    另外:Union FS 是有最大層數限制的,比如 AUFS,曾經是最大不得超過 42 層,現在是不得超過 127 層。

     

    Dockerfile 正確寫法:

     1 FROM debian:stretch
     2 
     3 RUN buildDeps='gcc libc6-dev make wget' \
     4     && apt-get update \
     5     && apt-get install -y $buildDeps \
     6     && wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz" \
     7     && mkdir -p /usr/src/redis \
     8     && tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1 \
     9     && make -C /usr/src/redis \
    10     && make -C /usr/src/redis install \
    11     && rm -rf /var/lib/apt/lists/* \
    12     && rm redis.tar.gz \
    13     && rm -r /usr/src/redis \
    14     && apt-get purge -y --auto-remove $buildDeps

    這裏沒有使用很多個 RUN 對應不同的命令,而是僅僅使用一個 RUN 指令,並使用 && 將各個所需命令串聯起來。將之前的 8 層,簡化為了 1 層,且後面刪除了不需要的包和目錄。在撰寫 Dockerfile 的時候,要經常提醒自己,這並不是在寫 Shell 腳本,而是在定義每一層該如何構建。因此鏡像構建時,一定要確保每一層只添加真正需要添加的東西,任何無關的東西都應該清理掉。

    很多人初學 Docker 製作出了很臃腫的鏡像的原因之一,就是忘記了每一層構建的最後一定要清理掉無關文件。

     

    COPY 複製文件

    格式:

    1 COPY [--chown=<user>:<group>] <源路徑>... <目標路徑>
    2 COPY [--chown=<user>:<group>] ["<源路徑1>",... "<目標路徑>"]

     

    COPY 指令將從構建上下文目錄中 <源路徑> 的文件/目錄複製到新的一層的鏡像內的 <目標路徑> 位置。如:

    COPY package.json /usr/src/app/

     

    <源路徑> 可以是多個,甚至可以是通配符,其通配符規則要滿足 Go 的 filepath.Match 規則,如:

    1 COPY hom* /mydir/
    2 COPY hom?.txt /mydir/

    <目標路徑> 可以是容器內的絕對路徑,也可以是相對於工作目錄的相對路徑(工作目錄可以用 WORKDIR 指令來指定)。目標路徑不需要事先創建,如果目錄不存在會在複製文件前先行創建缺失目錄。

    此外,還需要注意一點,使用 COPY 指令,源文件的各種元數據都會保留。比如讀、寫、執行權限、文件變更時間等。這個特性對於鏡像定製很有用。特別是構建相關文件都在使用 Git 進行管理的時候。

    在使用該指令的時候還可以加上 –chown=<user>:<group> 選項來改變文件的所屬用戶及所屬組。

    1 COPY --chown=55:mygroup files* /mydir/
    2 COPY --chown=bin files* /mydir/
    3 COPY --chown=1 files* /mydir/
    4 COPY --chown=10:11 files* /mydir/

     

    ADD 更高級的複製文件

    ADD 指令和 COPY 的格式和性質基本一致。但是在 COPY 基礎上增加了一些功能。

    如果 <源路徑> 為一個 tar 壓縮文件的話,壓縮格式為 gzip, bzip2 以及 xz 的情況下,ADD 指令將會自動解壓縮這個壓縮文件到 <目標路徑> 去。

    在某些情況下,如果我們真的是希望複製個壓縮文件進去,而不解壓縮,這時就不可以使用 ADD 命令了。

    在 Docker 官方的 Dockerfile 最佳實踐文檔 中要求,盡可能的使用 COPY,因為 COPY 的語義很明確,就是複製文件而已,而 ADD 則包含了更複雜的功能,其行為也不一定很清晰。最適合使用 ADD 的場合,就是所提及的需要自動解壓縮的場合。

    特別說明:在 COPY 和 ADD 指令中選擇的時候,可以遵循這樣的原則,所有的文件複製均使用 COPY 指令,僅在需要自動解壓縮的場合使用 ADD。

    在使用該指令的時候還可以加上 –chown=<user>:<group> 選項來改變文件的所屬用戶及所屬組。

    1 ADD --chown=55:mygroup files* /mydir/
    2 ADD --chown=bin files* /mydir/
    3 ADD --chown=1 files* /mydir/
    4 ADD --chown=10:11 files* /mydir/

     

    WORKDIR 指定工作目錄

    格式為 WORKDIR <工作目錄路徑>

    使用 WORKDIR 指令可以來指定工作目錄(或者稱為當前目錄),以後各層的當前目錄就被改為指定的目錄,如該目錄不存在,WORKDIR 會幫你建立目錄。

    之前提到一些初學者常犯的錯誤是把 Dockerfile 等同於 Shell 腳本來書寫,這種錯誤的理解還可能會導致出現下面這樣的錯誤:

    1 RUN cd /app
    2 RUN echo "hello" > world.txt

    如果將這個 Dockerfile 進行構建鏡像運行后,會發現找不到 /app/world.txt 文件,或者其內容不是 hello。原因其實很簡單,在 Shell 中,連續兩行是同一個進程執行環境,因此前一個命令修改的內存狀態,會直接影響后一個命令;而在 Dockerfile 中,這兩行 RUN 命令的執行環境根本不同,是兩個完全不同的容器。這就是對 Dockerfile 構建分層存儲的概念不了解所導致的錯誤。

    之前說過每一個 RUN 都是啟動一個容器、執行命令、然後提交存儲層文件變更。第一層 RUN cd /app 的執行僅僅是當前進程的工作目錄變更,一個內存上的變化而已,其結果不會造成任何文件變更。而到第二層的時候,啟動的是一個全新的容器,跟第一層的容器更完全沒關係,自然不可能繼承前一層構建過程中的內存變化。

    因此如果需要改變以後各層的工作目錄的位置,那麼應該使用 WORKDIR 指令。

     

    USER 指定當前用戶

    格式:USER <用戶名>[:<用戶組>]

    USER 指令和 WORKDIR 相似,都是改變環境狀態並影響以後的層。WORKDIR 是改變工作目錄,USER 則是改變之後層的執行 RUN, CMD 以及 ENTRYPOINT 這類命令的身份。

    當然,和 WORKDIR 一樣,USER 只是幫助你切換到指定用戶而已,這個用戶必須是事先建立好的,否則無法切換。

    1 RUN groupadd -r redis && useradd -r -g redis redis
    2 USER redis
    3 RUN [ "redis-server" ]

     

    如果以 root 執行的腳本,在執行期間希望改變身份,比如希望以某個已經建立好的用戶來運行某個服務進程,不要使用 su 或者 sudo,這些都需要比較麻煩的配置,而且在 TTY 缺失的環境下經常出錯。建議使用 gosu。

    1 # 建立 redis 用戶,並使用 gosu 換另一個用戶執行命令
    2 RUN groupadd -r redis && useradd -r -g redis redis
    3 # 下載 gosu
    4 RUN wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/1.7/gosu-amd64" \
    5     && chmod +x /usr/local/bin/gosu \
    6     && gosu nobody true
    7 # 設置 CMD,並以另外的用戶執行
    8 CMD [ "exec", "gosu", "redis", "redis-server" ]

     

    VOLUME 定義匿名卷

    格式為:

    1 VOLUME ["<路徑1>", "<路徑2>"...]
    2 VOLUME <路徑>

    之前我們說過,容器運行時應該盡量保持容器存儲層不發生寫操作,對於數據庫類需要保存動態數據的應用,其數據庫文件應該保存於卷(volume)中。為了防止運行時用戶忘記將動態文件所保存目錄掛載為卷,在 Dockerfile 中,我們可以事先指定某些目錄掛載為匿名卷,這樣在運行時如果用戶不指定掛載,其應用也可以正常運行,不會向容器存儲層寫入大量數據。

     

    VOLUME /data

    這裏的 /data 目錄就會在運行時自動掛載為匿名卷,任何向 /data 中寫入的信息都不會記錄進容器存儲層,從而保證了容器存儲層的無狀態化。當然,運行時可以覆蓋這個掛載設置。比如:

    docker run -d -v mydata:/data xxxx

    在這行命令中,就使用了 mydata 這個命名卷掛載到了 /data 這個位置,替代了 Dockerfile 中定義的匿名卷的掛載配置。

     

    EXPOSE 聲明端口

    格式為 EXPOSE <端口1> [<端口2>...]

    EXPOSE 指令是聲明運行時容器提供服務端口,這隻是一個聲明,在運行時並不會因為這個聲明應用就會開啟這個端口的服務。在 Dockerfile 中寫入這樣的聲明有兩個好處,一個是幫助鏡像使用者理解這個鏡像服務的守護端口,以方便配置映射;另一個用處則是在運行時使用隨機端口映射時,也就是 docker run -P 時,會自動隨機映射 EXPOSE 的端口。

    要將 EXPOSE 和在運行時使用 -p <宿主端口>:<容器端口> 區分開來。-p,是映射宿主端口和容器端口,換句話說,就是將容器的對應端口服務公開給外界訪問,而 EXPOSE 僅僅是聲明容器打算使用什麼端口而已,並不會自動在宿主進行端口映射。

     

    ENTRYPOINT 入口點

    ENTRYPOINT 的格式和 RUN 指令格式一樣,分為 exec 格式和 shell 格式

    ENTRYPOINT 的目的和 CMD 一樣,都是在指定容器啟動程序及參數。ENTRYPOINT 在運行時也可以替代,不過比 CMD 要略顯繁瑣,需要通過 docker run 的參數 –entrypoint 來指定。

    當指定了 ENTRYPOINT 后,CMD 的含義就發生了改變,不再是直接的運行其命令,而是將 CMD 的內容作為參數【】傳給 ENTRYPOINT 指令,換句話說實際執行時,將變為:

    <ENTRYPOINT> "<CMD>"

     

    那麼有了 CMD 后,為什麼還要有 ENTRYPOINT 呢?這種 <ENTRYPOINT> “<CMD>“ 有什麼好處么?讓我們來看幾個場景。

    場景一:讓鏡像變成像命令一樣使用

    假設我們需要一個得知自己當前公網 IP 的鏡像,那麼可以先用 CMD 來實現:

    1 FROM centos:7.7.1908
    2 CMD [ "curl", "-s", "ifconfig.io" ]

     

    假如我們使用 docker build -t myip . 來構建鏡像的話,如果我們需要查詢當前公網 IP,只需要執行:

    1 $ docker run myip
    2 183.226.75.148

     

    嗯,這麼看起來好像可以直接把鏡像當做命令使用了,不過命令總有參數,如果我們希望加參數呢?比如從上面的 CMD 中可以看到實質的命令是 curl,那麼如果我們希望显示 HTTP 頭信息,就需要加上 -i 參數。那麼我們可以直接加 -i 參數給 docker run myip 么?

    1 $ docker run myip -i
    2 docker: Error response from daemon: OCI runtime create failed: container_linux.go:348: starting container process caused "exec: \"-i\": executable file not found in $PATH": unknown.
    3 ERRO[0000] error waiting for container: context canceled

     

    我們可以看到可執行文件找不到的報錯,executable file not found。之前我們說過,跟在鏡像名後面的是 command【Usage: docker run [OPTIONS] IMAGE [COMMAND] [ARG…]】,運行時會替換 CMD 的默認值。因此這裏的 -i 替換了原來的 CMD,而不是添加在原來的 curl -s ifconfig.io 後面。而 -i 根本不是命令,所以自然找不到。

    那麼如果我們希望加入 -i 這參數,我們就必須重新完整的輸入這個命令:

    $ docker run myip curl -s ifconfig.io -i

     

    這顯然不是很好的解決方案,而使用 ENTRYPOINT 就可以解決這個問題。現在我們重新用 ENTRYPOINT 來實現這個鏡像:

    1 FROM centos:7.7.1908
    2 ENTRYPOINT [ "curl", "-s", "ifconfig.io" ]

     

    使用 docker build -t myip2 . 構建完成后,這次我們再來嘗試直接使用 docker run myip2 -i:

     1 $ docker run myip2 
     2 183.226.75.148
     3 
     4 $ docker run myip2 -i
     5 HTTP/1.1 200 OK
     6 Date: Sun, 19 Apr 2020 02:20:48 GMT
     7 Content-Type: text/plain; charset=utf-8
     8 Content-Length: 15
     9 Connection: keep-alive
    10 Set-Cookie: __cfduid=d76a2e007bbe7ec2d230b0a6636d115151587262848; expires=Tue, 19-May-20 02:20:48 GMT; path=/; domain=.ifconfig.io; HttpOnly; SameSite=Lax
    11 CF-Cache-Status: DYNAMIC
    12 Server: cloudflare
    13 CF-RAY: 586326015c3199a1-LAX
    14 alt-svc: h3-27=":443"; ma=86400, h3-25=":443"; ma=86400, h3-24=":443"; ma=86400, h3-23=":443"; ma=86400
    15 cf-request-id: 0231d614d9000099a1e10d7200000001
    16 
    17 183.226.75.148

     

    可以看到,這次成功了。這是因為當存在 ENTRYPOINT 后,CMD 的內容將會作為參數傳給 ENTRYPOINT,而這裏 -i 就是新的 CMD,因此會作為參數傳給 curl,從而達到了我們預期的效果。

     

    場景二:應用運行前的準備工作

    啟動容器就是啟動主進程,但有些時候,啟動主進程前,需要一些準備工作。

    比如 mysql 類的數據庫,可能需要一些數據庫配置、初始化的工作,這些工作要在最終的 mysql 服務器運行之前解決。

    此外,可能希望避免使用 root 用戶去啟動服務,從而提高安全性,而在啟動服務前還需要以 root 身份執行一些必要的準備工作,最後切換到服務用戶身份啟動服務。或者除了服務外,其它命令依舊可以使用 root 身份執行,方便調試等。

    這些準備工作是和容器 CMD 無關的,無論 CMD 是什麼,都需要事先進行一個預處理的工作。這種情況下,可以寫一個腳本,然後放入 ENTRYPOINT 中去執行,而這個腳本會將接到的參數(也就是 <CMD>)作為命令,在腳本最後執行。比如官方鏡像 redis 中就是這麼做的:

    1 FROM alpine:3.4
    2 ...
    3 RUN addgroup -S redis && adduser -S -G redis redis
    4 ...
    5 ENTRYPOINT ["docker-entrypoint.sh"]
    6 
    7 EXPOSE 6379
    8 CMD [ "redis-server" ]

     

    可以看到其中為了 redis 服務創建了 redis 用戶,並在最後指定了 ENTRYPOINT 為 docker-entrypoint.sh 腳本。

    1 #!/bin/sh
    2 ...
    3 # allow the container to be started with `--user`
    4 if [ "$1" = 'redis-server' -a "$(id -u)" = '0' ]; then
    5     chown -R redis .
    6     exec su-exec redis "$0" "$@"
    7 fi
    8 
    9 exec "$@"

     

    該腳本的內容就是根據 CMD 的內容來判斷,如果是 redis-server 的話,則切換到 redis 用戶身份啟動服務器,否則依舊使用 root 身份執行。比如:

    1 $ docker run -it redis id
    2 uid=0(root) gid=0(root) groups=0(root)

     

    CMD 容器啟動命令

    CMD 指令的格式和 RUN 相似,也是兩種格式和一種特殊格式:

    1 shell 格式:CMD <命令>
    2 exec 格式:CMD ["可執行文件", "參數1", "參數2"...]
    3 參數列表格式:CMD ["參數1", "參數2"...]。在指定了 ENTRYPOINT 指令后,用 CMD 指定具體的參數。

     

    之前介紹容器的時候曾經說過,Docker 不是虛擬機,容器就是進程。既然是進程,那麼在啟動容器的時候,需要指定所運行的程序及參數。CMD 指令就是用於指定默認的容器主進程的啟動命令的。

    在指令格式上,一般推薦使用 exec 格式,這類格式在解析時會被解析為 JSON 數組,因此一定要使用雙引號 “,而不要使用單引號。

    如果使用 shell 格式的話,實際的命令會被包裝為 sh -c 的參數的形式進行執行。比如:

    CMD echo $HOME

     

    在實際執行中,會將其變更為:

    CMD [ "sh", "-c", "echo $HOME" ]

     

    這就是為什麼我們可以使用環境變量的原因,因為這些環境變量會被 shell 進行解析處理。

    提到 CMD 就不得不提容器中應用在前台執行和後台執行的問題。這是初學者常出現的一個混淆。

    Docker 不是虛擬機,容器中的應用都應該以前台執行,而不是像虛擬機、物理機裏面那樣,用 systemd 去啟動後台服務,容器內沒有後台服務的概念

    對於容器而言,其啟動程序就是容器應用進程,容器就是為了主進程而存在的,主進程退出,容器就失去了存在的意義,從而退出,其它輔助進程不是它需要關心的東西。

    一些初學者將 CMD 寫為:

    CMD service nginx start

     

    使用 service nginx start 命令,則是希望 upstart 來以後台守護進程形式啟動 nginx 服務。而剛才說了 CMD service nginx start 會被理解為 CMD [ “sh”, “-c”, “service nginx start”],因此主進程實際上是 sh。那麼當 service nginx start 命令結束后,sh 也就結束了,sh 作為主進程退出了,自然就會令容器退出。

    正確的做法是直接執行 nginx 可執行文件,並且要求以前台形式運行。比如:

    CMD ["nginx", "-g", "daemon off;"]

     

    構建鏡像案例-Nginx

    構建文件

     1 [root@docker01 make03]# pwd
     2 /root/docker_test/make03
     3 [root@docker01 make03]# ll
     4 total 12
     5 -rw-r--r-- 1 root root 720 Apr 19 16:46 Dockerfile
     6 -rw-r--r-- 1 root root  95 Apr 19 16:19 entrypoint.sh
     7 -rw-r--r-- 1 root root  22 Apr 19 16:18 index.html
     8 [root@docker01 make03]# cat Dockerfile   # Dockerfile文件
     9 # 基礎鏡像
    10 FROM centos:7.7.1908
    11 
    12 # 維護者
    13 MAINTAINER lightzhang lightzhang@xxx.com
    14 
    15 # 命令:做了些什麼操作
    16 RUN echo 'nameserver 223.5.5.5' > /etc/resolv.conf && echo 'nameserver 223.6.6.6' >> /etc/resolv.conf
    17 RUN curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo && curl -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
    18 RUN yum install -y nginx-1.16.1 && yum clean all
    19 RUN echo "daemon off;" >> /etc/nginx/nginx.conf
    20 
    21 # 添加文件
    22 COPY index.html /usr/share/nginx/html/index.html
    23 COPY entrypoint.sh /usr/local/bin/entrypoint.sh
    24 
    25 # 對外暴露端口聲明
    26 EXPOSE 80
    27 
    28 # 執行
    29 ENTRYPOINT ["sh", "entrypoint.sh"]
    30 
    31 # 執行命令
    32 CMD ["nginx"]
    33 
    34 [root@docker01 make03]# cat index.html   # 訪問文件
    35 nginx in docker, html
    36 [root@docker01 make03]# cat entrypoint.sh   # entrypoint 文件
    37 #!/bin/bash
    38 if [ "$1" = 'nginx' ]; then
    39     exec nginx -c /etc/nginx/nginx.conf
    40 fi
    41 exec "$@"

     

    構建鏡像

     1 [root@docker01 make03]# docker build -t base/nginx:1.16.1 .
     2 Sending build context to Docker daemon  4.608kB
     3 Step 1/11 : FROM centos:7.7.1908
     4  ---> 08d05d1d5859
     5 Step 2/11 : MAINTAINER lightzhang lightzhang@xxx.com
     6  ---> Using cache
     7  ---> 1dc29e78d94f
     8 Step 3/11 : RUN echo 'nameserver 223.5.5.5' > /etc/resolv.conf && echo 'nameserver 223.6.6.6' >> /etc/resolv.conf
     9  ---> Using cache
    10  ---> 19398ad9b023
    11 Step 4/11 : RUN curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo && curl -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
    12  ---> Using cache
    13  ---> b2451c5856c5
    14 Step 5/11 : RUN yum install -y nginx-1.16.1 && yum clean all
    15  ---> Using cache
    16  ---> 291f27cae4df
    17 Step 6/11 : RUN echo "daemon off;" >> /etc/nginx/nginx.conf
    18  ---> Using cache
    19  ---> 115e07b6313e
    20 Step 7/11 : COPY index.html /usr/share/nginx/html/index.html
    21  ---> Using cache
    22  ---> 9d714d2e2a84
    23 Step 8/11 : COPY entrypoint.sh /usr/local/bin/entrypoint.sh
    24  ---> Using cache
    25  ---> b16983911b56
    26 Step 9/11 : EXPOSE 80
    27  ---> Using cache
    28  ---> d8675d6c2d43
    29 Step 10/11 : ENTRYPOINT ["sh", "entrypoint.sh"]
    30  ---> Using cache
    31  ---> 802a1a67db37
    32 Step 11/11 : CMD ["nginx"]
    33  ---> Using cache
    34  ---> f2517b4d5510
    35 Successfully built f2517b4d5510
    36 Successfully tagged base/nginx:1.16.1

     

    發布容器與端口查看

     1 [root@docker01 ~]# docker run -d -p 80:80 --name mynginx_v2 base/nginx:1.16.1   # 啟動容器
     2 50a45a0894d8669308de7c70d47c96db8cd8990d3e34d1d125e5289ed062f126
     3 [root@docker01 ~]# 
     4 [root@docker01 ~]# docker ps 
     5 CONTAINER ID   IMAGE               COMMAND                  CREATED         STATUS         PORTS                NAMES
     6 50a45a0894d8   base/nginx:1.16.1   "sh entrypoint.sh ng…"   3 minutes ago   Up 3 minutes   0.0.0.0:80->80/tcp   mynginx_v2
     7 [root@docker01 ~]# netstat -lntup  # 端口查看
     8 Active Internet connections (only servers)
     9 Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
    10 tcp        0      0 127.0.0.1:25            0.0.0.0:*               LISTEN      1634/master         
    11 tcp        0      0 0.0.0.0:111             0.0.0.0:*               LISTEN      1/systemd           
    12 tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      1349/sshd           
    13 tcp6       0      0 ::1:25                  :::*                    LISTEN      1634/master         
    14 tcp6       0      0 :::111                  :::*                    LISTEN      1/systemd           
    15 tcp6       0      0 :::80                   :::*                    LISTEN      13625/docker-proxy  
    16 tcp6       0      0 :::8080                 :::*                    LISTEN      2289/docker-proxy   
    17 tcp6       0      0 :::22                   :::*                    LISTEN      1349/sshd           
    18 udp        0      0 0.0.0.0:1021            0.0.0.0:*                           847/rpcbind         
    19 udp        0      0 0.0.0.0:111             0.0.0.0:*                           1/systemd           
    20 udp6       0      0 :::1021                 :::*                                847/rpcbind         
    21 udp6       0      0 :::111                  :::*                                1/systemd

     

    瀏覽器訪問

    http://172.16.1.31/

     

     

      

     

     

    ———END———
    如果覺得不錯就關注下唄 (-^O^-) !

     

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    新北清潔公司,居家、辦公、裝潢細清專業服務

    ※別再煩惱如何寫文案,掌握八大原則!

    網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

    ※超省錢租車方案

    ※教你寫出一流的銷售文案?

    網頁設計最專業,超強功能平台可客製化

  • Python 網絡爬蟲實戰:爬取 B站《全職高手》20萬條評論數據

    Python 網絡爬蟲實戰:爬取 B站《全職高手》20萬條評論數據

    本周我們的目標是:B站(嗶哩嗶哩彈幕網 https://www.bilibili.com )視頻評論數據。

    我們都知道,B站有很多號稱“鎮站之寶”的視頻,擁有着數量極其恐怖的評論和彈幕。所以這次我們的目標就是,爬取B站視頻的評論數據,分析其為何會深受大家喜愛。

    首先去調研一下,B站評論數量最多的視頻是哪一個。。。好在已經有大佬已經統計過了,我們來看一哈!

    ​【B站大數據可視化】B站評論數最多的視頻究竟是?來自 <https://www.bilibili.com/video/av34900167/>

     

    嗯?《全職高手》,有點意思,第一集和最後一集分別佔據了評論數量排行榜的第二名和第一名,遠超了其他很多很火的番。那好,就拿它下手吧,看看它到底強在哪兒。

    廢話不多說,先去B站看看這部神劇到底有多好看 https://www.bilibili.com/bangumi/play/ep107656

    額,需要開通大會員才能觀看。。。

    好吧,不看就不看,不過好在雖然視頻看不了,評論卻是可以看的。

    感受到它的恐怖了嗎?63w6條的評論!9千多頁!果然是不同凡響啊。

    接下來,我們就開始編寫爬蟲,爬取這些數據吧。

     

    使用爬蟲爬取網頁一般分為四個階段:分析目標網頁,獲取網頁內容,提取關鍵信息,輸出保存。

    1. 分析目標網頁

    • 首先觀察評論區結構,發現評論區為鼠標點擊翻頁形式,共 9399 頁,每一頁有 20 條評論,每條評論中包含 用戶名、評論內容、評論樓層、時間日期、點贊數等信息展示。

    • 接着我們按 F12 召喚出開發者工具,切換到Network。然後用鼠標點擊評論翻頁,觀察這個過程有什麼變化,並以此來制定我們的爬取策略。

    • 我們不難發現,整個過程中 URL 不變,說明評論區翻頁不是通過 URL 控制。而在每翻一頁的時候,網頁會向服務器發出這樣的請求(請看 Request URL)。

    • 點擊 Preview 欄,可以切換到預覽頁面,也就是說,可以看到這個請求返回的結果是什麼。下面是該請求返回的 json 文件,包含了在 replies 里包含了本頁的評論數據。在這個 json 文件里,我們可以發現,這裏面包含了太多的信息,除了網頁上展示的信息,還有很多沒展示出來的信息也有,簡直是挖到寶了。不過,我們這裏用不到,通通忽略掉,只挑我們關注的部分就好了。

    2. 獲取網頁內容

    網頁內容分析完畢,可以正式寫代碼爬了。

     1 import requests
     2 
     3 def fetchURL(url):
     4     '''
     5     功能:訪問 url 的網頁,獲取網頁內容並返回
     6     參數:
     7         url :目標網頁的 url
     8     返回:目標網頁的 html 內容
     9     '''
    10     headers = {
    11         'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
    12         'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36',
    13     }
    14     
    15     try:
    16         r = requests.get(url,headers=headers)
    17         r.raise_for_status()
    18         print(r.url)
    19         return r.text
    20     except requests.HTTPError as e:
    21         print(e)
    22         print("HTTPError")
    23     except requests.RequestException as e:
    24         print(e)
    25     except:
    26         print("Unknown Error !")
    27         
    28 
    29 if __name__ == '__main__':
    30     url = 'https://api.bilibili.com/x/v2/reply?callback=jQuery172020326544171595695_1541502273311&jsonp=jsonp&pn=2&type=1&oid=11357166&sort=0&_=1541502312050'
    31     html = fetchURL(url)
    32     print(html)

    不過,在運行過後,你會發現,403 錯誤,服務器拒絕了我們的訪問。

    運行結果:

    403 Client Error: Forbidden for url: https://api.bilibili.com/x/v2/reply?callback=jQuery172020326544171595695_1541502273311&jsonp=jsonp&pn=2&type=1&oid=11357166&sort=0&_=1541502312050
    HTTPError
    None

    同樣的,這個請求放瀏覽器地址欄裏面直接打開,會變403,什麼也訪問不到。

    這是我們本次爬蟲遇到的第一個坑。在瀏覽器中能正常返迴響應,但是直接打開請求鏈接時,卻會被服務器拒絕。(我第一反應是 cookie ,將瀏覽器中的 cookie 放入爬蟲的請求頭中,重新訪問,發現沒用),或許這也算是一個小的反爬蟲機制吧。

    網上查閱資料之後,我找到了解決的方法(雖然不了解原理),原請求的 URL 參數如下:

    callback = jQuery1720913511919053787_1541340948898
    jsonp = jsonp
    pn = 2
    type = 1
    oid = 11357166&sort=0
    _ = 1541341035236

    其中,真正有用的參數只有三個:pn(頁數),type(=1)和oid(視頻id)。刪除其餘不必要的參數之後,用新整理出的url去訪問,成功獲取到評論數據。

    https://api.bilibili.com/x/v2/reply?type=1&oid=11357166&pn=2

    然後,在主函數中,通過寫一個 for 循環,通過改變 pn 的值,獲取每一頁的評論數據。

    1 if __name__ == '__main__':
    2     for page in range(0,9400):
    3         url = 'https://api.bilibili.com/x/v2/reply?type=1&oid=11357166&pn=' + str(page)
    4         html = fetchURL(url)

     

    3. 提取關鍵信息

    通過 json 庫對獲取到的響應內容進行解析,然後提取我們需要的內容:樓層,用戶名,性別,時間,評價,點贊數,回複數。

     1 import json
     2 import time
     3 
     4 def parserHtml(html):
     5     '''
     6     功能:根據參數 html 給定的內存型 HTML 文件,嘗試解析其結構,獲取所需內容
     7     參數:
     8             html:類似文件的內存 HTML 文本對象
     9     '''
    10     s = json.loads(html)
    11 
    12     for i in range(20):
    13         comment = s['data']['replies'][i]
    14 
    15         # 樓層,用戶名,性別,時間,評價,點贊數,回複數
    16         floor = comment['floor']
    17         username = comment['member']['uname']
    18         sex = comment['member']['sex']
    19         ctime = time.strftime("%Y-%m-%d %H:%M:%S",time.localtime(comment['ctime']))
    20         content = comment['content']['message']
    21         likes = comment['like']
    22         rcounts = comment['rcount']
    23 
    24         print('--'+str(floor) + ':' + username + '('+sex+')' + ':'+ctime)
    25         print(content)
    26         print('like : '+ str(likes) + '      ' + 'replies : ' + str(rcounts))
    27         print('  ')
    部分運行結果如下:
    --204187:day可可鈴(保密):2018-11-05 18:16:22
    太太又出本了,這次真的木錢了(´;ω;`)
    like : 1      replies : 0
      
    --204186:長夜未央233(女):2018-11-05 16:24:52
    12區打卡
    like : 2      replies : 0
      
    --204185:果然還是人渣一枚(男):2018-11-05 13:48:09
    貌似忘來了好幾天
    like : 1      replies : 1
      
    --204183:day可可鈴(保密):2018-11-05 13:12:38
    要準備去學校了,萬惡的期中考試( ´_ゝ`)
    like : 2      replies : 0
      
    --204182:拾秋以恭弘=叶 恭弘(保密):2018-11-05 12:04:19
    11月5日打卡( ̄▽ ̄)
    like : 1      replies : 0
      
    --204181:芝米士噠(女):2018-11-05 07:53:43
    這次是真的錯過了一個億[蛆音娘_扶額]
    like : 2      replies : 1
    
    

    4. 保存輸出

    我們把這些數據以 csv 的格式保存於本地,即完成了本次爬蟲的全部任務。下面附上爬蟲的全部代碼。

      1 import requests
      2 import json
      3 import time
      4 
      5 def fetchURL(url):
      6     '''
      7     功能:訪問 url 的網頁,獲取網頁內容並返回
      8     參數:
      9         url :目標網頁的 url
     10     返回:目標網頁的 html 內容
     11     '''
     12     headers = {
     13         'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
     14         'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36',
     15     }
     16     
     17     try:
     18         r = requests.get(url,headers=headers)
     19         r.raise_for_status()
     20         print(r.url)
     21         return r.text
     22     except requests.HTTPError as e:
     23         print(e)
     24         print("HTTPError")
     25     except requests.RequestException as e:
     26         print(e)
     27     except:
     28         print("Unknown Error !")
     29         
     30 
     31 def parserHtml(html):
     32     '''
     33     功能:根據參數 html 給定的內存型 HTML 文件,嘗試解析其結構,獲取所需內容
     34     參數:
     35             html:類似文件的內存 HTML 文本對象
     36     '''
     37     try:
     38         s = json.loads(html)
     39     except:
     40         print('error')
     41         
     42     commentlist = []
     43     hlist = []
     44 
     45     hlist.append("序號")
     46     hlist.append("名字")
     47     hlist.append("性別")
     48     hlist.append("時間")
     49     hlist.append("評論")
     50     hlist.append("點贊數")
     51     hlist.append("回複數")
     52 
     53     #commentlist.append(hlist)
     54 
     55     # 樓層,用戶名,性別,時間,評價,點贊數,回複數
     56     for i in range(20):
     57         comment = s['data']['replies'][i]
     58         blist = []
     59 
     60         floor = comment['floor']
     61         username = comment['member']['uname']
     62         sex = comment['member']['sex']
     63         ctime = time.strftime("%Y-%m-%d %H:%M:%S",time.localtime(comment['ctime']))
     64         content = comment['content']['message']
     65         likes = comment['like']
     66         rcounts = comment['rcount']
     67 
     68         blist.append(floor)
     69         blist.append(username)
     70         blist.append(sex)
     71         blist.append(ctime)
     72         blist.append(content)
     73         blist.append(likes)
     74         blist.append(rcounts)
     75 
     76         commentlist.append(blist)
     77 
     78     writePage(commentlist)
     79     print('---'*20)
     80 
     81 def writePage(urating):
     82     '''
     83         Function : To write the content of html into a local file
     84         html : The response content
     85         filename : the local filename to be used stored the response
     86     '''
     87     
     88     import pandas as pd
     89     dataframe = pd.DataFrame(urating)
     90     dataframe.to_csv('Bilibili_comment5-1000條.csv', mode='a', index=False, sep=',', header=False)
     91 
     92 
     93 if __name__ == '__main__':
     94     for page in range(0,9400):
     95         url = 'https://api.bilibili.com/x/v2/reply?type=1&oid=11357166&pn=' + str(page)
     96         html = fetchURL(url)
     97         parserHtml(html)
     98 
     99         # 為了降低被封ip的風險,每爬20頁便歇5秒。
    100         if page%20 == 0:
    101             time.sleep(5)

     

    寫在最後

    在爬取過程中,還是遇到了很多的小坑的。

    1. 請求的 url 不能直接用,需要對參數進行篩選整理后才能訪問。

    2. 爬取過程其實並不順利,因為如果爬取期間如果有用戶發表評論,則請求返回的響應會為空導致程序出錯。所以在實際爬取過程中,記錄爬取的位置,以便出錯之後從該位置繼續爬。(並且,挑選深夜一兩點這種發帖人數少的時間段,可以極大程度的減少程序出錯的機率)

    3. 爬取到的數據有多處不一致,其實這個不算是坑,不過這裏還是講一下,免得產生困惑。

            a. 就是評論區樓層只到了20多萬,但是評論數量卻有63萬多條,這個不一致主要是由於B站的評論是可以回復的,回復的評論也會計算到總評論數里。我們這裏只爬樓層的評論,而評論的回復則忽略,只統計回複數即可。

            b. 評論區樓層在20萬條左右,但是我們最後爬取下來的數據只有18萬條左右,反覆檢查爬蟲程序及原網站后發現,這個屬於正常現象,因為有刪評論的情況,評論刪除之後,後面的樓層並不會重新排序,而是就這樣把刪掉的那層空下了。導致樓層數和評論數不一致。

     

     

     如果文章中有哪裡沒有講明白,或者講解有誤的地方,歡迎在評論區批評指正,或者掃描下面的二維碼,加我微信,大家一起學習交流,共同進步。

     

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※教你寫出一流的銷售文案?

    ※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

    ※回頭車貨運收費標準

    ※別再煩惱如何寫文案,掌握八大原則!

    ※超省錢租車方案

    ※產品缺大量曝光嗎?你需要的是一流包裝設計!

  • 全球再生能源發電總量 5年內有望增長5成

    摘錄自2019年10月21日自由時報報導

    國際能源署(IEA)針對全球可再生能源市場進行2019年至2024年的分析與預測,21日發布《2019年可再生能源》(Renewables 2019)年度報告。報告預估,全球可再生能源的發電總量,未來5年內可提升50%,相當於增加1200吉瓦(GW);可再生能源的發電佔比將從目前的26%提升到30%。

    報告指出,可再生能源中預估成長最快速的是太陽能,其發電量未來5年內約可增加600吉瓦,且發電成本可降低15%至35%;屋頂太陽能系統的數量未來5年內有望增加逾一倍,達到1億座。

    本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※帶您來了解什麼是 USB CONNECTOR  ?

    ※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

    ※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!

    ※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

    ※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

    ※教你寫出一流的銷售文案?

  • 非洲豬瘟疫情防控 南韓今年確診11起

    摘錄自2020年01月12日中央通訊社南韓報導

    南韓環境部和國立環境科學院今天(12日)表示,自去年10月3日首次確診以來,截至10日共有66起確診感染非洲豬瘟(ASF)病毒,僅今年就有11起確診,疫情防控上仍有很大挑戰。

    南韓聯合新聞通訊社報導,去年10月(18起)、11月(15起)、12月(22起)平均每天有0.5~0.7起確診,但今年以來每天發現1起以上感染死豬。江原道華川地區最近首次發現感染非洲豬瘟的野豬屍體。

    之前僅在京畿道漣川(26起)、坡州(22起)、江原道鐵原(17起)發現感染非洲豬瘟的野豬屍體,此次擴散到華川。

    報導說,政府9日召開會議檢討非洲豬瘟疫情應對情況。雖然確診疫情數在增加,但政府官員認為,這是防疫過程中的自然現象。不過由於家豬傳播非洲豬瘟病毒的可能性沒有完全消失,將繼續加強防疫監管。

    本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※為什麼 USB CONNECTOR 是電子產業重要的元件?

    網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

    ※台北網頁設計公司全省服務真心推薦

    ※想知道最厲害的網頁設計公司"嚨底家"!

    新北清潔公司,居家、辦公、裝潢細清專業服務

    ※推薦評價好的iphone維修中心

  • 番茄感染病毒 法國出現首批確診案例

    摘錄自2020年2月18日中央社報導

    法國農業部今天(18日)表示,法國最西邊菲尼斯泰爾省(Finistere)的番茄植物已遭一種毀滅性病毒污染,這種病毒可能導致全部作物付之一炬。

    法新社報導,法國農業部表示,已隔離一座農場,並將摧毀充滿番茄的多座溫室,目前沒有已知的治療方法。

    這種病毒稱作「番茄褐色皺紋果病毒」(ToBRFV),可造成番茄出現粗糙變色斑塊,以致番茄賣不出去。官員先前警告,這種病毒的散播對農夫將有「重大經濟後果」。

    這種病毒對人類無害。2014年於以色列的溫室中傳出首例,之後傳播至歐洲及美洲。

    本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

    台北網頁設計公司這麼多該如何選擇?

    ※智慧手機時代的來臨,RWD網頁設計為架站首選

    ※評比南投搬家公司費用收費行情懶人包大公開

    ※幫你省時又省力,新北清潔一流服務好口碑

    ※回頭車貨運收費標準

  • 貝斯女王島走出油污陰霾 褐鵜鶘庇護區揭牌

    摘錄自2020年3月3日公視報導

    美國路易斯安那州的貝斯女王島,是褐鵜鶘主要的棲地,過去因為遭到漏油事件重創,環境危害嚴重。不過在肇事的英國石油公司賠償下,將擴建庇護區。

    路易斯安那州官員為重建的水鳥庇護區揭牌同時表示,過去人類對牠們棲地所造成的傷害長達10年,現在要還給牠們更乾淨、更安全的家。各界也希望今年夏天,貝斯女王島能跟往年一樣有約6500隻褐鵜鶘,以及約3000隻較小的水鳥遷徙到這裡築巢。

    2010年墨西哥灣漏油事件,造成11人死亡,87天內超過1億加侖的原油洩漏。當時貝斯女王島72公里海岸線布滿油汙,褐鵜鶘全身浸泡在黑色汙泥的景象極為駭人,島上許多植物被遭毀,造成的生態浩劫引發全球擔憂。肇事的英國石油公司賠償200億美元,其中部分金額用來擴建養護1700公頃的海岸跟小島,今年還將投入8億美元持續重建工程。

    本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

    網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

    ※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

    南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!

    ※教你寫出一流的銷售文案?

    ※超省錢租車方案

  • 專家針對武漢肺炎警告 都市人長期處於空污下 恐增加感染死亡風險

    環境資訊中心綜合外電;姜唯 編譯;林大利 審校

    本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

    網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

    ※Google地圖已可更新顯示潭子電動車充電站設置地點!!

    ※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

    ※別再煩惱如何寫文案,掌握八大原則!

    網頁設計最專業,超強功能平台可客製化

  • Dell 將於 2040 年全面轉用再生能源

    摘錄自2019年11月13日unwire HK報導

    隨著更多的企業響應環保,作為知名的電腦公司 DELL 在近日亦宣佈了新的可持續發展計劃,指公司所有設施的 75% 電力將會使用可再生能源,直至 2040 年時將預計可獲 100% 的電力,並同時在計劃在過程中提高公司在生產及供應鏈上的能源效益,以達致低排放的目標為環保出一分力。

    DELL 在早前宣佈公司將進行「Progress Made Real」的計劃,計劃內容主要包括在消費者購買的每一項設備時會回收同一污染水平的產品,以及在生產電力方面採用可再生能源。DELL 指出到 2030 年時公司一半以上的設備將會由回收材料或可再生物料而生產,在包裝上則會全面使用可重覆利用的物料。

    不過 DELL 就並未透露公司是否會增加旗下所有裝置的使用壽命,但就指出對電子製造商而言,應對氣候變化的最佳方法是避免所有電子產品送往堆填區,而是重覆使用及物盡其用。

    本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

    ※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

    ※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

    南投搬家公司費用需注意的眉眉角角,別等搬了再說!

    新北清潔公司,居家、辦公、裝潢細清專業服務

    ※教你寫出一流的銷售文案?

  • 不敵客訴壓力 澳洲超市延後對塑膠袋收費

    摘錄自2018年8月3日蘋果日報澳洲報導

    澳洲一間大型連鎖超市原本要實施塑膠袋需收費政策,希望可推動「減塑」為環保出一分力,不料顧客對此大感不滿,政策推出後已經第2次延長收費期限。

    連鎖超市科爾斯(Coles)自上月1日起停用一次性塑膠袋,改向顧客提供可重複使用、質料更耐用的塑膠袋作過渡,直至本周三(1日)為止。超市原定顧客此後若索取塑膠袋,每個須收取15澳分(約3.4元台幣)。

    然而科爾斯周三發聲明指,自禁用一次性塑膠袋後,有顧客反映需要更多過渡時間,以適應使用可重複使用塑膠袋,集團因此決定在昆士蘭、新南威爾斯、維多利亞及西澳洲等地繼續提供免費塑膠袋至8月29日,而南澳洲、塔斯馬尼亞等地區則仍繼續收費。

    本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

    網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

    ※想知道最厲害的網頁設計公司"嚨底家"!

    ※幫你省時又省力,新北清潔一流服務好口碑

    ※別再煩惱如何寫文案,掌握八大原則!

    ※產品缺大量曝光嗎?你需要的是一流包裝設計!

  • 湄公河跨國水資源爭奪戰 寮國沙耶武里大壩爭議中即將啟用

    湄公河跨國水資源爭奪戰 寮國沙耶武里大壩爭議中即將啟用

    環境資訊中心外電;姜唯 翻譯;林大利 審校;稿源:ENS

    位於寮國北部湄公河的沙耶武里水壩將在數日內正式啟用。沙耶武里水壩是湄公河主流下游的第一座水壩,它的啟用象徵著湄公河命運的重要轉折點。

    湄公河長4,350公里,是世界第12長河,排水量世界第八。發源於青藏高原,流經中國、緬甸、寮國和泰國,接著湧入柬埔寨和越南的沖積平原和三角洲。

    沙耶武里水壩的主要目的是水力發電,其95%的發電量將由泰國電力局購買。

    沙耶武里水壩打從一開始就是一個爭議性的工程,許多人擔心它對河流系統的作用,包括使湄公河的洄游魚類和沈積物難以往下游移動,可能連鄰國都會受影響。

    大壩對環境的影響進而威脅流域內居民的糧食來源、生計和社會文化體系。

    沙耶武里水壩即將完工。照片來源:

    許多專家認為,湄公河上游中國境內已經建了六座水壩,寮國甚至柬埔寨下游還要再蓋,已經讓湄公河深陷危機。

    沙耶武里水壩諮詢過程中,有許多利害關係者表示關切,質疑資料和研究是否充分。

    越南政府呼籲暫停所有主流上水壩的建設10年,以進一步研究、更深入地了解河流系統和水壩的可能影響。

    泰國湄公河沿岸的社區代表於2012年向泰國行政法院提起訴訟,質疑泰國向沙耶武里水壩購買電力的計畫。此訴訟案別具指標性,但經過數次上訴,七年後的今日仍懸而未決。

    儘管如此,沙耶武里水壩的開發並沒有停止,開發商重新設計以減輕疑慮。

    後續的大壩工程計畫也持續在進行。本月,湄公河委員會宣布開始對湄公河下游的第五座主流水壩瑯勃拉邦進行事前諮商。

    在沙耶武里水壩啟用前,美國非營利組織國際河網(International Rivers)發布了關於水壩的新報告。該組織邀請兩位獨立專家針對湄公河委員會今年稍早發布的沙耶武里水壩設計變更審查報告發表評論。

    兩位專家分別是澳洲雪梨大學人文地理學教授賀屈(Philip Hirsch)博士和英格蘭諾桑比亞大學社會科學副教授亨森格斯(Oliver Hensengerth)博士。他們檢視沙耶武里水壩如何成為主流水壩決策模式的基準,強調「迫切需要一個真正的區域性標準程序來保護湄公河的未來。」

    國際河網的聲明指出,雖然國際河網自身的立場是認為大壩的開發正在「扼殺」湄公河,但該專家評論的目的並非批評或評估湄公河委員會的管理審查報告,而是在試圖「找出關鍵點,討論它們對沙耶武里水壩和其他規劃中或興建中水壩對湄公河下游主流以及該地區內的影響。」

    沙耶武里水壩開發前的地景樣貌。照片來源: (CC BY 2.0)

    23日,一場針對國際河網報告的座談會在泰國曼谷外國記者俱樂部舉行,與會學者、社區和民間社團熱烈討論沙耶武里水壩工程的歷史、決策過程缺陷、進行中的活動以及對生態系統與居民的影響。

    國際河網認為,沙耶武里水壩興建過程「工程先行,研究後補」的做法很不負責任。(詳見)

    湄公河沖積平原和三角洲是全世界農業產量極高、生物多樣性極豐富的水域之一,但是海平面上升、土地沉降、上游超過126個規劃中水壩以及各式各樣三角洲水利基礎設施讓人們不得不對水力發電的潛在問題感到憂心。

    國際河網不是唯一一個對湄公河流域感到擔憂的環境組織。

    丹麥DHI顧問集團針對湄公河三角洲進行的研究得出的結論是,「即使是現有最佳的魚道技術,也可能無法因應大量的魚類遷徙。在高峰時期,遷徙魚群最多可達每小時300萬條。此外,可能也難以滿足該流域數百種魚類有百百種遷移方式。」

    根據22日在寮國首都永珍發布的最新報告《》,負責管理流域水壩開發的湄公河委員會也對此表示關注。

    湄公河委員會成立於1995年,是一個政府間組織,直接與柬埔寨、寮國、泰國和越南政府合作,共同管理共享水資源和湄公河的永續發展。

    該組織是水務外交的區域平台,也是維持該區域永續發展的水資源管理知識中心。

    湄公河委員會報告警告:「主流水流體系明顯永久性改變,沉積物被阻攔造成泥沙流量大量減少,濕地持續喪失,河流生態環境惡化,捕撈漁業的壓力不斷增加以及目前水開發設施和用水資訊共享有限」,是湄公河流域國家面臨的主要挑戰。

    「我們現在必須解決這些問題,盡可能減少對環境的損害,並在僅剩的濕地和河邊生態環境消失之前加以保護,同時利用更穩定且有所增加的旱季流量,實現湄公河地區最佳永續發展。」湄公河委員會執行長An Pich Hatda博士在啟用儀式上對來自四個湄公河國家、近100位官員說。

    最新的流域狀況報告建議:「必須緊急採取更積極的區域性流域規劃和管理方法,並加強系統性地共享資訊,並嚴格監控河流流量,以因應這些流域挑戰。」

    Dam Development Is ‘Silencing’ the Mekong River BANGKOK, Thailand, October 24, 2019 (ENS)

     In five days, the Xayaburi Hydropower Project on the Mekong River in northern Laos will formally begin operations. As the first dam on the lower Mekong mainstream, this marks a turning point for the Mekong River.

    The Mekong River is 4,350 kilometers (2,703 miles) long, ranked 12th in length and eighth in water discharge in the world. The river originates in the Tibetan Plateau and flows through China, Myanmar, Laos, and Thailand before pouring into the alluvial floodplains and delta in Cambodia and Vietnam.

    The main purpose of the Xayaburi dam is to produce hydroelectric power, 95 percent of which is to be purchased by the Electricity Generating Authority of Thailand.

    From the outset, the Xayaburi dam was a controversial project due to widespread concerns over its expected impacts on the river system, including transboundary impacts in neighboring countries.

    Major predicted impacts include the destruction of Mekong migratory fisheries and trapping of sediment, preventing it from traveling downstream.

    The dam’s environmental impacts, in turn, threaten the food, livelihoods and socio-cultural systems of populations residing within the river basin.

    Many experts believe that the Mekong, already suffering from the impacts of six dams installed in China on the Upper Mekong, and with more dams planned downstream in Laos and possibly Cambodia, is in crisis.

    During the Xayaburi dam consultation process, many stakeholders raised concerns over the project and questioned the adequacy of the data and studies.

    The Vietnamese government called for a project suspension and a 10-year moratorium on all mainstream dams pending further study to better understand the river system and the impacts of planned dams.

    In Thailand, community representatives along the Mekong River filed a landmark lawsuit in the Thai Administrative Court challenging Thailand’s power purchase from the project. Originally filed in 2012, following several appeals, the lawsuit remains pending more than seven years later.

    Despite this, the Xayaburi dam moved forward, with the developers undertaking a redesign in an effort to mitigate concerns.

    Subsequent dam projects have followed. This month, the Mekong River Commission announced the commencement of Prior Consultation for Luang Prabang, the fifth lower Mekong mainstream dam to undergo the process.

    In the lead-up to the commissioning of the Xayaburi dam, the U.S.-based nonprofit group International Rivers issued a new report on the dam. The group asked two independent experts to provide comments on the Mekong River Commission’s review of the Xayaburi redesign, released earlier this year.

    The report of the experts, Dr. Philip Hirsch, professor of Human Geography at the University of Sydney, Australia; and Dr. Oliver Hensengerth, associate professor of social sciences at Northumbria University, England, examines the pattern of Xayaburi in setting a benchmark for decisions on mainstream dams and highlights “the urgent need for a truly regional approach to safeguard the Mekong’s future.”

    Although International Rivers says dam development is “silencing” the Mekong River, this expert commentary is not intended as a critique or assessment of the MRC Review, said the group in a statement. “Rather, it seeks to draw out key points and discuss their implications for Xayaburi and other dams under construction or consideration on the lower Mekong mainstream and within the region.”

    On Wednesday, a panel discussion of the International Rivers report with academic, community and civil society speakers at the Foreign Correspondents’ Club of Thailand in Bangkok provoked comments on the project’s history, its flawed decision-making process, the ongoing campaigns, and Xayaburi’s implications for the ecosystems and people of the Mekong Basin.

    International Rivers has described the “build first, study later” approach propagated by the Xayaburi Dam process as “a dangerously irresponsible model for dam-building in the Mekong.”

    To read the report, “Review of Design Changes Made for the Xayaburi Hydropower Project,” click .

    The Mekong floodplains and delta are among the most agriculturally productive and biologically diverse waterscapes of the world, but sea level rise, land subsidence, and the proposed upstream development of over 126 hydropower dams and extensive delta-based water infrastructure have raised concerns about the potential impacts on the hydrology of the region.

    International Rivers is not the only environmental group with concerns about the Mekong River Basin.

    A Mekong Delta Study conducted by Denmark’s DHI Consulting Group concluded it was likely “that even the best available fish passage technologies’ may not be able to handle either the massive volume of fish migrations, which during peak periods can reach up to three million fish per hour, or the diversity of migration strategies that characterise the hundreds of fish species in the basin.”

    The Mekong River Commission, which governs the dam development of the basin, is also concerned, according to the latest report, State of the Basin Report 2018, released on Tuesday in Vientiane, the Laotian capital city.

    Established in 1995, the Mekong River Commission, MRC, is an inter-governmental organization that works directly with the governments of Cambodia, Laos, Thailand, and Vietnam to jointly manage the shared water resources and the sustainable development of the Mekong River.

    The organization serves as a regional platform for water diplomacy as well as a knowledge hub of water resources management for the sustainable development of the region.

    The MRC report warns, “The apparent permanent modification of mainstream flow regime, the substantial reduction in sediment flows due to sediment trapping, the continuing loss of wetlands, the deterioration of riverine habitats, the growing pressures on capture fisheries, and the limited information sharing on current water development facilities and water use,” are some of the major challenges facing countries in the Mekong Basin.

    “We need to address these issues now in order to minimize further environmental harm and protect remaining wetlands and riverine habitats before they are gone, while leveraging the benefits of more secure and increased dry season flows and achieving a more optimal and sustainable development of the Mekong basin,” Dr. An Pich Hatda, chief executive officer of the MRC Secretariat, told nearly 100 officials from the four MRC countries at the launch ceremony.

    This latest State of the Basin Report advises that “a more proactive regional approach to basin planning and management, with an enhanced and systematic information sharing mechanism and robust monitoring of river flow must be put in place urgently to address these basin-wide challenges.”

    ※ 全文及圖片詳見:

    作者

    如果有一件事是重要的,如果能為孩子實現一個願望,那就是人類與大自然和諧共存。

    於特有生物研究保育中心服務,小鳥和棲地是主要的研究對象。是龜毛的讀者,認為龜毛是探索世界的美德。

    延伸閱讀

    本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

    新北清潔公司,居家、辦公、裝潢細清專業服務

    ※別再煩惱如何寫文案,掌握八大原則!

    ※教你寫出一流的銷售文案?

    ※超省錢租車方案

    FB行銷專家,教你從零開始的技巧