Başarısız bir "liman işçisi inşası" nın dosya sistemini nasıl inceleyebilirim?


272

cpanmÇeşitli projeler için temel görüntü olarak bir grup Perl modülünü kurmak için geliştirme sürecimiz için yeni bir Docker görüntüsü oluşturmaya çalışıyorum .

Dockerfile geliştirilirken, cpanmbazı modüller temiz yüklenmediğinden bir hata kodu döndürür.

Daha aptfazla şey yüklemem gerektiğine eminim .

Benim sorum, /.cpanm/workgünlükleri incelemek için çıktıda belirtilen dizini nerede bulabilirim ? Genel durumda, başarısız bir docker buildkomutun dosya sistemini nasıl inceleyebilirim ?

Sabah düzenleme Mermi ısırıp çalıştırdıktan sonra findkeşfettim

/var/lib/docker/aufs/diff/3afa404e[...]/.cpanm

Bu güvenilir mi, yoksa ihtiyacım olan her şeyi elde edene kadar bir "çıplak" konteyner oluşturmak ve elle manuel olarak çalıştırmak daha iyi miyim?


hakkında /var/lib/docker/aufs/diff/3afa404e[...]/.cpanm
Docker'ın içsel

Yanıtlar:


355

RUNDocker her Dockerfile komutunu başarıyla çalıştırdığında , görüntü dosya sistemindeki yeni bir katman işlenir . Kolayca yeni bir kapsayıcı başlatmak için bu katman kimliklerini görüntü olarak kullanabilirsiniz.

Aşağıdaki Docker dosyasını alın:

FROM busybox
RUN echo 'foo' > /tmp/foo.txt
RUN echo 'bar' >> /tmp/foo.txt

ve inşa et:

$ docker build -t so-2622957 .
Sending build context to Docker daemon 47.62 kB
Step 1/3 : FROM busybox
 ---> 00f017a8c2a6
Step 2/3 : RUN echo 'foo' > /tmp/foo.txt
 ---> Running in 4dbd01ebf27f
 ---> 044e1532c690
Removing intermediate container 4dbd01ebf27f
Step 3/3 : RUN echo 'bar' >> /tmp/foo.txt
 ---> Running in 74d81cb9d2b1
 ---> 5bd8172529c1
Removing intermediate container 74d81cb9d2b1
Successfully built 5bd8172529c1

Artık yeni bir konteyner başlayabilir 00f017a8c2a6, 044e1532c690ve 5bd8172529c1:

$ docker run --rm 00f017a8c2a6 cat /tmp/foo.txt
cat: /tmp/foo.txt: No such file or directory

$ docker run --rm 044e1532c690 cat /tmp/foo.txt
foo

$ docker run --rm 5bd8172529c1 cat /tmp/foo.txt
foo
bar

tabii ki dosya sistemini keşfetmek ve komutları denemek için bir kabuk başlatmak isteyebilirsiniz:

$ docker run --rm -it 044e1532c690 sh      
/ # ls -l /tmp
total 4
-rw-r--r--    1 root     root             4 Mar  9 19:09 foo.txt
/ # cat /tmp/foo.txt 
foo

Dockerfile komutundan biri başarısız olduğunda, yapmanız gereken , önceki katmanın kimliğini aramak ve bu id'den oluşturulan bir kapta bir kabuk çalıştırmaktır:

docker run --rm -it <id_last_working_layer> bash -il

Konteynerde bir kez:

  • başarısız olan komutu deneyin ve sorunu yeniden oluşturun
  • sonra komutu düzeltin ve test edin
  • son olarak Dockerfile dosyanızı sabit komutla güncelleyin

Son çalışma katmanından çalışmak yerine başarısız olan gerçek katmanı denemeniz gerekiyorsa, Drew'un cevabına bakın .


2
Evet öyle. Dockerfile dosyasında hata ayıklamak istediğinizde hata ayıklamak için amaçlanan kapsayıcı tutma noktası yoktur.
Thomasleveil

1
Tamam, bu gerçekten süper yararlı oldu, ama bir konteyner inşa başarısız olursa, bu hile çalıştığı söyledi kabın hash ile kullanamıyorum sorunu var. RUN başarısız olursa hiçbir görüntü oluşturulur. Hiç temizlenmemiş olan ara kaba takabilir miyim?
Altreus

6
Dockerfile komutundan biri başarısız olduğunda, yapmanız gereken, önceki katmanın kimliğini aramak ve bu kimliğin kabuğuna sahip bir kapsayıcı çalıştırmaktır: docker run --rm -it <id_last_working_layer> bash -ilve kapta bir kez sorunu yeniden oluşturamayan komutu deneyin, ardından komutu düzeltin ve test edin, son olarak Dockerfile dosyanızı sabit komutla güncelleyin.
Thomasleveil

2
Ayrıca, docker diff <container>belirli bir katman üzerinde yapılan belirli dosya sistemi değişikliklerinin (bu görüntü için tüm dosya sistemine eklenen, silinen veya değiştirilen dosyalar) kapsamlı bir listesini alabilirsiniz.
L0j1k

14
Bunun işe yaramadığını düşündüm çünkü dedi Unable to find image 'd5219f1ffda9:latest' locally. Ancak, birden fazla kimlik türü ile kafam karıştı. Görünüşe göre, "Okuyor ..." diyenleri değil, okların hemen arkasındaki kimlikleri kullanmanız gerekiyor.
rspeer

201

Üst yanıt, başarısız komuttan hemen önce durumu incelemek istediğiniz durumda işe yarar.

Ancak soru, başarısız kabın durumunun nasıl inceleneceğini soruyor. Benim durumumda, başarısız komut birkaç saat süren bir yapıdır, bu yüzden başarısız komuttan önce geri sarmak ve tekrar çalıştırmak uzun zaman alır ve çok yararlı değildir.

Buradaki çözüm başarısız olan kapsayıcıyı bulmaktır:

$ docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                          PORTS               NAMES
6934ada98de6        42e0228751b3        "/bin/sh -c './utils/"   24 minutes ago      Exited (1) About a minute ago                       sleepy_bell

Bir görüntüye verin:

$ docker commit 6934ada98de6
sha256:7015687976a478e0e94b60fa496d319cdf4ec847bcd612aecf869a72336e6b83

Ve sonra görüntüyü çalıştırın [gerekirse bash çalışıyor]:

$ docker run -it 7015687976a4 [bash -il]

Şimdi, derlemenin, başarısızlığa neden olan komutu çalıştırmadan önce yerine, başarısız olduğu zamanda bakıyorsunuz.


İlgi alanı dışında, neden kapsayıcıdan yeni bir resim oluşturmanız gerekiyor? Neden sadece kabı başlatmıyorsunuz? Başarısız kapsayıcıdan oluşturulan bir görüntü çalışabiliyorsa, durdurulan / başarısız kapsayıcı da çalışabilir mi? Yoksa bir şey mi kaçırıyorum?
nmh

@nmh Çünkü başarısız komutunu tekrar çalıştırmak zorunda kalmadan, başarısız durumdaki bir kapsayıcıyı yakalayıp incelemenize izin verir. Bazen başarısız komutun yürütülmesi dakika veya daha uzun sürebilir, bu nedenle bu, başarısız durumu etiketlemek için uygun bir yoldur. Örneğin, şu anda birkaç dakika süren başarısız bir C ++ kitaplığı derlemesinin günlüklerini incelemek için bu yaklaşımı kullanıyorum. Edit - Sadece Drew [onun] durumda, başarısız komut birkaç saat süren bir yapı olduğunu söyledi, bu yüzden başarısız komuttan önce geri sarma ve tekrar çalıştırmak uzun zaman alır ve çok yararlı değil dedi.
Jaime Soto

@nmh Başarısız kapsayıcıyı başlatmaya çalışırken sorun, kapsayıcının start komutunun normal olarak yararlı olması için değiştirilmesi gerektiğidir. Başarısız kapsayıcıyı yeniden başlatmayı denerseniz, yeniden başarısız olan komutu çalıştırır ve başladığınız yere geri dönersiniz. Bir görüntü oluşturarak farklı bir başlat komutuyla bir kapsayıcı başlatabilirsiniz.
Centimane

2
Eğer DOCKER_BUILDKIT=1inşa etmek için kullanıyorsanızDockerfile
Clintm

@ Nmh'nin noktasına gelince - derleme çıktısından hemen sonraysanız görüntüyü vermeniz gerekmez. Docker konteyner cp kullanabilirsinizBaşarısız oluşturma kapsayıcısından dosya sonuçlarını ayıklamak için .
whoisthemachine

7

Docker , her başarılı RUNsatırdan sonra tüm dosya sistemi durumunu önbelleğe alır .

Bilerek:

  • Arızalı önce son durumunu incelemek üzere RUNkomuta, Dockerfile (yanı sıra her türlü müteakip bunu açıklama RUN, daha sonra çalıştırmak komutları) docker buildve docker runtekrar.
  • başarısız komuttan sonra durumu incelemek için RUN, || trueonu başarılı olmaya zorlamak için eklemeniz yeterlidir ; sonra yukarıdaki gibi devam edin (sonraki tüm RUNkomutları açıklayın, çalıştırın docker buildve çalıştırın docker run)

Tada, Docker'ın dahili veya katman kimlikleriyle uğraşmaya gerek yok ve bonus olarak Docker, yeniden yapılması gereken iş miktarını otomatik olarak en aza indirir.


1
Bu, DOCKER_BUILDKIT kullanılırken özellikle yararlı bir yanıttır, çünkü buildkit yukarıda listelenenlerle aynı çözümleri desteklemiyor gibi görünmektedir.
M. Anthony Aiello

3

Derleme adımı hatalarını ayıklamak gerçekten çok can sıkıcı bir durum.

Bulduğum en iyi çözüm, gerçek iş yapan her adımın başarılı olduğundan emin olmak ve başarısız olanlardan sonra bir kontrol eklemek. Bu şekilde, inceleyebileceğiniz başarısız adımın çıktılarını içeren kararlı bir katman elde edersiniz.

Satırdan sonra bir örnek içeren bir Dockerfile # Run DB2 silent installer:

#
# DB2 10.5 Client Dockerfile (Part 1)
#
# Requires
#   - DB2 10.5 Client for 64bit Linux ibm_data_server_runtime_client_linuxx64_v10.5.tar.gz
#   - Response file for DB2 10.5 Client for 64bit Linux db2rtcl_nr.rsp 
#
#
# Using Ubuntu 14.04 base image as the starting point.
FROM ubuntu:14.04

MAINTAINER David Carew <carew@us.ibm.com>

# DB2 prereqs (also installing sharutils package as we use the utility uuencode to generate password - all others are required for the DB2 Client) 
RUN dpkg --add-architecture i386 && apt-get update && apt-get install -y sharutils binutils libstdc++6:i386 libpam0g:i386 && ln -s /lib/i386-linux-gnu/libpam.so.0 /lib/libpam.so.0
RUN apt-get install -y libxml2


# Create user db2clnt
# Generate strong random password and allow sudo to root w/o password
#
RUN  \
   adduser --quiet --disabled-password -shell /bin/bash -home /home/db2clnt --gecos "DB2 Client" db2clnt && \
   echo db2clnt:`dd if=/dev/urandom bs=16 count=1 2>/dev/null | uuencode -| head -n 2 | grep -v begin | cut -b 2-10` | chgpasswd && \
   adduser db2clnt sudo && \
   echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers

# Install DB2
RUN mkdir /install
# Copy DB2 tarball - ADD command will expand it automatically
ADD v10.5fp9_linuxx64_rtcl.tar.gz /install/
# Copy response file
COPY  db2rtcl_nr.rsp /install/
# Run  DB2 silent installer
RUN mkdir /logs
RUN (/install/rtcl/db2setup -t /logs/trace -l /logs/log -u /install/db2rtcl_nr.rsp && touch /install/done) || /bin/true
RUN test -f /install/done || (echo ERROR-------; echo install failed, see files in container /logs directory of the last container layer; echo run docker run '<last image id>' /bin/cat /logs/trace; echo ----------)
RUN test -f /install/done

# Clean up unwanted files
RUN rm -fr /install/rtcl

# Login as db2clnt user
CMD su - db2clnt

0

Ne yapacağım aşağıdaki Dockerfile yorum ve rahatsız edici çizgi dahil olmaktır. Ardından kapsayıcıyı çalıştırabilir ve docker komutlarını elle çalıştırabilir ve günlüklere her zamanki gibi bakabilirsiniz. Örneğin, Dockerfile

RUN foo
RUN bar
RUN baz

ve barda ölüyorum yapardım

RUN foo
# RUN bar
# RUN baz

Sonra

$ docker build -t foo .
$ docker run -it foo bash
container# bar
...grep logs...

Bu konuyu bulmadan önce ben de yapardım. Ancak yapının yeniden çalıştırılmasını gerektirmeyen daha iyi yollar var.
Aaron McMillin

@Aaron. Bana bu cevabı hatırlattığın için teşekkürler. Uzun zamandır bakmadım. Kabul edilen cevabın pratik cevap açısından neden bundan daha iyi olduğunu açıklar mısınız? Drew'un cevabının neden daha iyi olduğunu kesinlikle anladım. Kabul edilen cevabın hala yeniden çalıştırılması gerekiyor gibi görünüyor.
seanmcl

Aslında Drew'un cevabına oy verdim, kabul edilene değil. Her ikisi de yapıyı yeniden çalıştırmadan çalışır. Kabul edilen cevapta, başarısız komuttan hemen önce bir kabuğa atlayabilirsiniz (Hızlıysa hatayı görmek için tekrar çalıştırabilirsiniz). Ya da Drew'un cevabı ile başarısız komut çalıştıktan sonra bir kabuk alabilirsiniz (Onun durumunda başarısız komut uzun süredir çalışıyordu ve arkasında kalan durum incelenebilir).
Aaron McMillin
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.